Class Collection
Collection empowers table: unicity, sort and type-protection of datas (elements).
Type-protection
At creation time, you declare what type of elements is accepted: number, string or table.
This ensure that all added elements must respect that else error is raised.
As table are the root of any object/class, you can store almost everything in a Collection. tables can't be compared eachother so thoses Collections can't be uniquified nor sorted, contains and value comparison is not possible neither.
As a Java developer since more than 20 years, I'm used to work with
Collection and Map which offer powerful methods.
Here there are in Lua!
SMJavaCollections.mys is automatically included when you Include "SMUtils"
.
Differences between table and Collection
Better than long explanations, here are code/algorithm that demonstrate the differences.
Action | table | Collection | Notes |
---|---|---|---|
Creation | t = {} |
c = Collection:new(elementType, sortFunction) |
where elementType is "number" , "string" or "table" |
Add | tinsert(t, data) |
c:add(data) |
In the same table, you can insert numbers, strings and others types. Collection avoid this: more restrictive, less bugs. |
Add a set of data | for i=1,getn(datas) do tinsert(t, datas[i]) end |
c:addAll(anotherCollection) |
|
Read | print(t[2]) |
print(c:get(2)) |
With Collection, the data is guaranteed to have the type you want. |
Remove data at index 2 | tremove(t, 2) |
c:removeAt(2) |
|
Remove first "banana" | for i=1,getn(t) do if t[i]=="banana" then tremove(t, i) break end end |
c:remove("banana") |
|
Remove all "bananas" | Loop backward, move efficientfor i=getn(t),1,-1 do if t[i]=="banana" then tremove(t, i) end end |
c:removeAll("bananas") |
|
Get size | getn(t) |
c:size() |
|
Replace at index 2 | t[2] = "apple" |
c:replaceAt(2, "apple") |
|
Sort | sort(t, sortFunction) |
Nothing to do | Datas are sorted at insertion, if Collection is created with a sorting function |
Does it contain "apricot"? |
|
c:contains("apricot") |
|
Don't add "banana" if already in table | Loop. if no "banana" found then insert.local found = false for i=1,getn(t) do if t[i]=="banana" then found=true; break; end end if found==false then tinsert(t, "banana") end |
Nothing to do | At creation time, Collection may be a "set", i.e. a Collection of unique datas |
Get index of "apple" |
|
c:indexOf("apple") |
|
Get the first / last data |
|
c:first() or c:last() |
|
Get greatest/least data |
|
c:last() / c:first() |
for sorted Collection only |
Get all data before/after (or including) "banana" |
|
c:head("banana", inclusive) or c:tail("banana", inclusive) where inclusive is a boolean. |
|
Browse | for i=1,getn(t) do print(t[i]) end Backward browsing: for i=getn(t),1,-1 do...
|
c:iterator() while c:hasNext() do print(c:next()) end Backward browsing: c:reverseIterator() |
As you can notice, very simple operation are easier to write using table, but complex ones are really more friendly using Collection.
Collection should save you time, make your script more maintainables, and reduce errors because of type-protection of inserted datas.
Note on performance: Collection is backed on native Lua table. It's fast, but just a little bit less than working with tables.
If you are really concerned by CPU and memory optimization and perform a lot of simple operation on many tables,
you may prefer table to Collection.
If you are concerned by easy-to-read code and ready-to-use functions, Collection is for you.
For example, Collection is usless for building a large table of digital waveform (44100 numbers per second of sound).
Summary
Return type | Function and summary |
---|---|
Collection | new(string elementType, boolean unique, function sortFunction) Create a new Collection. |
int | add(elementType ...) Add elements (undefined liste size) one by one in the Collection. |
int | addAll(anotherTable) Add all elements of a table or Collection in this Collection. |
elementType | ceiling(elementType element) Returns the least element in this set greater than or equal to the given element, or nil if there is no such element. |
clear() Empty the Collection | |
boolean | contains(elementType element) Does Collection already contains element? |
boolean | containsAll(anotherTable) Does this Collection contains all the elements of anotherTable? |
debug() Debug a structure of this Collection in console, only if LOG_LEVEL = LOG_LEVEL_DEBUG . | |
elementType | first() Returns the first (least in case of sorted Set) element of this Collection |
elementType | floor(elementType element) Returns the greatest element in this set least than or equal to the given element, or nil if there is no such element. |
forEach(function fn) Apply transformation function fn to each element of this Collection. | |
elementType | get(number index) Returns the element at the specified index where 1 <= index <= size() |
boolean | hasNext(string iteratorName) While iterating, is there a next element? |
Collection | head(elementType element, boolean inclusive) Returns a partial copy of this Collection, with elements less (or equal, if inclusive = true) than the given element. |
elementType | higher(elementType element) Returns the least element in this set greater than to the given element, or nil if there is no such element. |
int | indexOf(elementType element) Returns the index of the first occurrence of the specified element in this Collection, or -1 if this Collection does not contain element. |
boolean | isEmpty() Is this Collection empty? |
boolean | isSet() Is this Collection a Set? |
iterator(string iteratorName) Starts or restarts an iterator on the Collection. | |
elementType | last() Returns the last (greatest if sorted) element in this set |
int | lastIndexOf(elementType element) Returns the index of the last occurrence of the specified element in this Collection, or -1 if this Collection does not contain the element. |
elementType | lower(elementType element) Returns the greatest element in this set least than to the given element, or nil if there is no such element. |
elementType | next(string iteratorName) While iterating, returns next element if :hasNext() , nil otherwise. |
print() Prints a debug structure of the Collection in console. | |
int | remove(elementType ...) Removes the first element of this Collection that equals the given element. |
int | removeAll(elements) Removes all elements of this Collection that:
|
elementType | removeAt(number index) Remove the element at the specified index and return deleted element |
elementType | replaceAt(number idx, elementType newElement) Replace the element at the specified index by the given newElement, returns replaced element. |
Collection | retainsAll(elements) Retains, in this Collection, only the elements that are contained in the specified table. |
reverseIterator(string iteratorName) Starts or restarts a reversed iterator on the Collection. | |
Collection | search(string regexp, boolean caseInsensitive) If the collection contains strings, search by a regexp and return a new Collection with same properties, containing the results. |
int | size() Returns the size of the Collection, the number of elements it contains. |
Collection | sub(elementType from, boolean fromInclusive, elementType to, boolean toInclusive) Returns a partial copy of this Collection, with elements between from and to. |
Collection | tail(elementType element, boolean inclusive) Returns a partial copy of this Collection, with elements greater (or equal, if inclusive = true) than the given element. |
table | toArray() Returns a Lua native table containing all elements of this Collection. |
Methods
Collection:new(string elementType, boolean unique, function sortFunction)
Create a new Collection.
Parameter | Type | Default | Description |
---|---|---|---|
elementType | string | "string" | "number" , "string" , "table" a Lua class or "mixed" . |
unique | boolean | false | Are elements unique (as Java Set)? or not (as Java ArrayList)? |
sortFunction | function | nil | if unique is true , sorting function can be provided, else elements stay in insertion order |
- Return
- Collection: A new empty Collection
- Error
- if elementType is wrong
Collection:add(elementType ...)
Add elements (undefined liste size) one by one in the Collection.
If Collection is a Set (unique values) and already contains element, nothing is added.
Parameter | Type | Default | Description |
---|---|---|---|
... | elementType | One or more elements to add |
- Return
- int: Number of inserted element.
- Error
- if the type of one element doesn't match constructor elementType argument.
Collection:addAll(anotherTable)
Add all elements of a table or Collection in this Collection.
Parameter | Type | Default | Description |
---|---|---|---|
anotherTable | A table, Collection:toArray() or Collection |
- Return
- int: The number of inserted elements
- Errors
- if anotherTable is not a table
- if one of anotherTable
type(element)
doesn't match constructor elementType parameter
Collection:contains(elementType element)
Does Collection already contains element?
Equivalent of Collection:indexOf(element)~=-1
Parameter | Type | Default | Description |
---|---|---|---|
element | elementType | element |
- Return
- boolean:
true
, ornil
(for false) - Errors
- if
type(element)
doesn't match constructor elementType parameter - if elements of this Collection are not comparables
Collection:containsAll(anotherTable)
Does this Collection contains all the elements of anotherTable?
Parameter | Type | Default | Description |
---|---|---|---|
anotherTable | A table or Collection:toArray() ) or Collection |
- Return
- boolean:
nil
(for >false) if at least one element of anotherTable is missing in this Collection - Errors
- if anotherTable contains one element which type doesn't match constructor elementType parameter
- if elements of this Collection are not comparables
Collection:clear()
Empty the Collection
Collection:forEach(function fn)
Apply transformation function fn to each element of this Collection.
If this Collection is a Set, probable duplicate elements after transformation, only one will be kept. If this Collection is sorted, elements are sorted after the transformations.
Parameter | Type | Default | Description |
---|---|---|---|
fn | function | A function that accept an element as argument and must return two values:
|
- Example
local c = Collection:new("string") c:addAll({"apple", "banana", "kiwi"}) c:forEach(function(element) print(element.."s"); end) --> apples, bananas, kiwis c:forEach(function(element) return strupper(element), true; end) --> all elements are now uppercase c:forEach(function(element) print(element); end) --> APPLE, BANANA, KIWI
Collection:get(number index)
Returns the element at the specified index where 1 <= index <= size()
Parameter | Type | Default | Description |
---|---|---|---|
index | number | index |
- Return
- elementType: an element
- Error
- if index is out of bounds
Collection:indexOf(elementType element)
Returns the index of the first occurrence of the specified element in this Collection, or -1 if this Collection does not contain element.
Parameter | Type | Default | Description |
---|---|---|---|
element | elementType | element |
- Return
- int: index between 1 and Collection:size(), or -1
- Errors
- if
type(element)
doesn't match constructor elementType parameter - if elements of this Collection are not comparables
- See
- Collection:lastIndexOf
- Example
local c = Collection:new("string") c:addAll({"apple", "banana", "apple", "kiwi"}) print(c:indexOf("apple")) --> 1 print(c:indexOf("cherry")) --gt; -1
Collection:isEmpty()
Is this Collection empty?
- Return
- boolean:
true
if has no element at all,nil
(for false) otherwise
Collection:isSet()
Is this Collection a Set?
A set is made of unique elements.
- Return
- boolean:
true
, ornil
(for false) - Example
Collection:new("string"):isSet() --> false Collection:new("string", true):isSet() --gt; true
Collection:lastIndexOf(elementType element)
Returns the index of the last occurrence of the specified element in this Collection, or -1 if this Collection does not contain the element.
Parameter | Type | Default | Description |
---|---|---|---|
element | elementType | element |
- Return
- int: index between 1 and Collection:size(), or -1
- Errors
- if
type(element)
doesn't match constructor elementType parameter - if elements of this Collection are not comparables
- See
- Collection:indexOf
- Example
local c = Collection:new("string") c:addAll({"apple", "banana", "apple", "kiwi"}) print(c:lastIndexOf("apple")) --gt; 3 print(c:lastIndexOf("cherry")) --gt; -1
Collection:remove(elementType ...)
Removes the first element of this Collection that equals the given element.
Parameter | Type | Default | Description |
---|---|---|---|
... | elementType | One or more element to remove |
- Return
- int: Number of element removed.
- Errors
- if type of one element doesn't match constructor elementType argument.
- if elements of this Collection are not comparables
Collection:removeAll(elements)
Removes all elements of this Collection that:
- equals elements if it's a number or a string
- are contained in elements, if it's a table or Collection
Parameter | Type | Default | Description |
---|---|---|---|
elements | number, string, table or Collection |
- Return
- int: Number of removals, between 0 and Collection:size()
- Errors
- if
type(element)
doesn't match constructor elementType parameter - if elements of this Collection are not comparables
Collection:removeAt(number index)
Remove the element at the specified index and return deleted element
Parameter | Type | Default | Description |
---|---|---|---|
index | number | 1 <= index <= size() |
- Return
- elementType: The removed element
- Error
- if index is out of bounds
Collection:replaceAt(number idx, elementType newElement)
Replace the element at the specified index by the given newElement, returns replaced element.
Parameter | Type | Default | Description |
---|---|---|---|
idx | number | 1 <= idx <= size() | |
newElement | elementType | newElement |
- Return
- elementType: the replaced element
- Errors
- if
type(newElement)
doesn't match constructor elementType parameter - if idx is out of bounds
Collection:retainsAll(elements)
Retains, in this Collection, only the elements that are contained in the specified table.
Parameter | Type | Default | Description |
---|---|---|---|
elements | List of elements to retain in this Collection, table (native or Collection:toArray() ) or a Collection |
- Return
- Collection: Collection of removed elements
- Errors
- if
type(element)
doesn't match constructor elementType parameter - if elements of this Collection are not comparables
- Example
local c = Collection:new("number") c:addAll({1,2,3,4,5,6,7,8,9,10}) local primes = Collection:new("number") primes:addAll({1,2,3,5,7}) local c2 = c:retainAll(primes) --gt; c now contains only primes 1, 2, 3, 5 and 7 --> c2 contains the removed elements: 4, 6, 8, 9 and 10.
Collection:size()
Returns the size of the Collection, the number of elements it contains.
- Return
- int: 0 or more
Collection:toArray()
Returns a Lua native table containing all elements of this Collection.
- Return
- table: table
Collection:first()
Returns the first (least in case of sorted Set) element of this Collection
- Return
- elementType: An element,
nil
if Collection is empty - See
- Collection:last
- Example
local c = Collection:new("number") c:addAll({2,4,6,1,3,5}) print(c:first()) --> 2 c = Collection:new("number", true, SORT_ASCENDING) c:addAll({2,4,6,1,3,5}) print(c:first()) --> 1 c = Collection:new("number", true, SORT_DESCENDING) c:addAll({2,4,6,1,3,5}) print(c:first()) --> 6
Collection:head(elementType element, boolean inclusive)
Returns a partial copy of this Collection, with elements less (or equal, if inclusive = true) than the given element.
Parameter | Type | Default | Description |
---|---|---|---|
element | elementType | element | |
inclusive | boolean | false | Include element in the result? |
- Return
- Collection: A Collection with same properties, can be empty.
- Errors
- if
type(element)
doesn't match constructor elementType parameter - if elements of this Collection are not comparables
- See
- Collection:sub
- Collection:tail
- Example
local c = Collection:new("number") c:addAll({1,2,3,5,7,11}) local h = c:head(5) -- or head(5, false) --> h contains 1, 2 and 3 h = c:head(5, true) --> h contains 1, 2, 3 and 5
Collection:last()
Returns the last (greatest if sorted) element in this set
- Return
- elementType: an element or
nil
if this Collection is empty - See
- Collection:first
- Example
local c = Collection:new("number") c:addAll({1,3,5,7,2,4,6}) print(c:last()) --> 6 c = Collection:new("number", true, SORT_ASCENDING) c:addAll({1,3,5,7,2,4,6}) print(c:last()) --> 7 c = Collection:new("number", true, SORT_DESCENDING) c:addAll({1,3,5,7,2,4,6}) print(c:last()) --> 1
Collection:sub(elementType from, boolean fromInclusive, elementType to, boolean toInclusive)
Returns a partial copy of this Collection, with elements between from and to.
Parameter | Type | Default | Description |
---|---|---|---|
from | elementType | from | |
fromInclusive | boolean | true | Include from in result? |
to | elementType | to | |
toInclusive | boolean | false | Include to in result ? |
- Return
- Collection: A new Collection with same properties, can be empty
- Errors
- if from >= to
- if
type(from)
ortype(to)
don't match constructor elementType parameter - if elements of this Collection are not comparables
- See
- Collection:head
- Collection:tail
- Example
local c = Collection:new("number") c:addAll({1,2,3,5,7,11}) local s = c:sub(5, false, 9, false) --> s contains 7 s = c:sub(5, true, 9, true) --> s contains 5 and 7 s = c:sub(5, true, 11, false) --> s contains 5 and 7 s = c:sub(5, true, 11, true) --> s contains 5, 7 and 11
Collection:tail(elementType element, boolean inclusive)
Returns a partial copy of this Collection, with elements greater (or equal, if inclusive = true) than the given element.
Parameter | Type | Default | Description |
---|---|---|---|
element | elementType | element | |
inclusive | boolean | false | Include element in the result? |
- Return
- Collection: A new Collection with same properties, can be empty
- Errors
- if
type(element)
doesn't match constructor elementType parameter - if elements of this Collection are not comparables
- See
- Collection:head
- Collection:sub
- Collection:head
- Collection:sub
- Example
local c = Collection:new("number") c:addAll({1,2,3,5,7,11}) local t = c:tail(5) -- or tail(5, false) --> t contains 7 and 11 t = c:tail(5, true) --> t contains 5, 7 and 11
Collection:search(string regexp, boolean caseInsensitive)
If the collection contains strings, search by a regexp and return a new Collection with same properties, containing the results.
Parameter | Type | Default | Description |
---|---|---|---|
regexp | string | regexp | |
caseInsensitive | boolean | false | Case insensitive search? Strings are strlower()ed, so the regexp must search in lower case. |
- Return
- Collection: Empty if no result found
- Error
- if constructor elementType parameter is not
"string"
Collection:ceiling(elementType element)
Returns the least element in this set greater than or equal to the given element, or nil
if there is no such element.
Parameter | Type | Default | Description |
---|---|---|---|
element | elementType | element |
- Return
- elementType: Existing element or
nil
- Errors
- if
type(element)
doesn't match constructor elementType parameter - if elements of this Collection are not comparables
- See
- Collection:floor
- Collection:higher
- Collection:lower
- Example
local c = Collection:new("number") c:addAll({1,2,3,5,7,11}) print(c:ceiling(3)) --> 3 print(c:ceiling(4)) --> 5 print(c:ceiling(14)) --> nil
Collection:floor(elementType element)
Returns the greatest element in this set least than or equal to the given element, or nil
if there is no such element.
Parameter | Type | Default | Description |
---|---|---|---|
element | elementType | element |
- Return
- elementType: An element or
nil
- Errors
- if
type(element)
doesn't match constructor elementType parameter - if elements of this Collection are not comparables
- See
- Collection:ceiling
- Collection:higher
- Collection:lower
- Example
local c = Collection:new("number") c:addAll({1,2,3,5,7,11}) print(c:floor(0)) --> nil print(c:floor(1)) --> 1 print(c:floor(4)) --> 3 print(c:floor(14)) --> 11
Collection:higher(elementType element)
Returns the least element in this set greater than to the given element, or nil
if there is no such element.
Parameter | Type | Default | Description |
---|---|---|---|
element | elementType | element |
- Return
- elementType: existing element or
nil
- Errors
- if
type(element)
doesn't match constructor elementType parameter - if elements of this Collection are not comparables
- See
- Collection:ceiling
- Collection:floor
- Collection:lower
- Example
local c = Collection:new("number") c:addAll({1,2,3,5,7,11}) print(c:higher(4)) --> 5 print(c:higher(5)) --> 7 print(c:higher(11)) --> nil
Collection:lower(elementType element)
Returns the greatest element in this set least than to the given element, or nil
if there is no such element.
Parameter | Type | Default | Description |
---|---|---|---|
element | elementType | element |
- Return
- elementType: existing element or
nil
- Errors
- if
type(element)
doesn't match constructor elementType parameter - if elements of this Collection are not comparables
- See
- Collection:ceiling
- Collection:floor
- Collection:higher
- Example
local c = Collection:new("number") c:addAll({1,2,3,5,7,11}) print(c:lower(4)) --> 3 print(c:higher(3)) --> 2 print(c:higher(1)) --> nil
Collection:iterator(string iteratorName)
Starts or restarts an iterator on the Collection.
An iterator is a convenient way to browse the Collection from first to last element with :hasNext()
and :next()
methods.
You can provide an iteratorName to run multiple iterators simultaneously, else the result would be hazardous.
Parameter | Type | Default | Description |
---|---|---|---|
iteratorName | string | nil |
Collection:reverseIterator(string iteratorName)
Starts or restarts a reversed iterator on the Collection.
A reverse iterator is a convenient way to browse the Collection from last to first element with :hasNext()
and :next()
methods.
You can provide an iteratorName to run multiple iterators simultaneously, else the result would be hazardous.
Parameter | Type | Default | Description |
---|---|---|---|
iteratorName | string | nil |
Collection:hasNext(string iteratorName)
While iterating, is there a next element?
You can provide an iteratorName to run multiple iterators simultaneously, else the result would be hazardous.
Parameter | Type | Default | Description |
---|---|---|---|
iteratorName | string | nil |
- Return
- boolean:
nil
(for false) if end of Collection is reached,true
if there are still some element to iterate - See
- Collection:next
- Collection:iterator
- Collection:reverseIterator
Collection:next(string iteratorName)
While iterating, returns next element if :hasNext()
, nil
otherwise.
You can provide an iteratorName to run multiple iterators simultaneously, else the result would be hazardous.
Parameter | Type | Default | Description |
---|---|---|---|
iteratorName | string | nil |
- Return
- elementType: An element or
nil
- See
- Collection:hasNext
- Collection:iterator
- Collection:reverseIterator
Collection:print()
Prints a debug structure of the Collection in console.
if you want it prints only if LOG_LEVEL = LOG_LEVEL_DEBUG
, use Collection:debug()
instead.
Collection:debug()
Debug a structure of this Collection in console, only if LOG_LEVEL = LOG_LEVEL_DEBUG
.