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.

Differences between table and Collection

Better than long explanations, here are code/algorithm that demonstrate the differences.

ActiontableCollectionNotes
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 efficient
for 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"?
  • Sort if needed, and loop untile "apricot" or a greater data is found
  • or loop the whole table untile "apricot" is found or end is reached
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"
  1. Sort if needed
  2. loop until first "apple" found or end reached
c:indexOf("apple")
Get the first / last data
  1. Sort if needed
  2. t[1] or t[getn(t)]
c:first() or c:last()
Get greatest/least data
  • Sort and return t[1] / t[getn(t)]
  • Or loop thought all data to find greatest / least
c:last() / c:first() for sorted Collection only
Get all data before/after (or including) "banana"
  1. Sort if needed
  2. Loop until "banana" is found
  3. Add previous/next datas to a table and return it.
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 typeFunction and summary
Collectionnew(string elementType, bool unique, function sortFunction)
Create a new Collection.
intadd(elementType element)
Add element in the Collection.
intaddAll(anotherTable)
Add all elements of a table or Collection in this Collection.
elementTypeceiling(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
boolcontains(elementType element)
Does Collection already contains element?
boolcontainsAll(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.
elementTypefirst()
Returns the first (least in case of sorted Set) element of this Collection
elementTypefloor(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.
elementTypeget(number index)
Returns the element at the specified index where 1 <= index <= size()
boolhasNext(string iteratorName)
While iterating, is there a next element?
Collectionhead(elementType element, bool inclusive)
Returns a partial copy of this Collection, with elements less (or equal, if inclusive = true) than the given element.
elementTypehigher(elementType element)
Returns the least element in this set greater than to the given element, or nil if there is no such element.
intindexOf(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.
boolisEmpty()
Is this Collection empty?
boolisSet()
Is this Collection a Set?
 iterator(string iteratorName)
Starts or restarts an iterator on the Collection.
elementTypelast()
Returns the last (greatest if sorted) element in this set
intlastIndexOf(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.
elementTypelower(elementType element)
Returns the greatest element in this set least than to the given element, or nil if there is no such element.
elementTypenext(string iteratorName)
While iterating, returns next element if :hasNext(), nil otherwise.
 print()
Prints a debug structure of the Collection in console.
intremove(elementType element)
Removes the first element of this Collection that equals the given element.
intremoveAll(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
elementTyperemoveAt(number index)
Remove the element at the specified index and return deleted element
elementTypereplaceAt(number idx, elementType newElement)
Replace the element at the specified index by the given newElement, returns replaced element.
CollectionretainsAll(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.
intsize()
Returns the size of the Collection, the number of elements it contains.
Collectionsub(elementType from, bool fromInclusive, elementType to, bool toInclusive)
Returns a partial copy of this Collection, with elements between from and to.
Collectiontail(elementType element, bool inclusive)
Returns a partial copy of this Collection, with elements greater (or equal, if inclusive = true) than the given element.
tabletoArray()
Returns a Lua native table containing all elements of this Collection.

Methods

Collection:new(string elementType, bool unique, function sortFunction)

Create a new Collection.

ParameterTypeDefaultDescription
elementTypestring"string""number", "string" or "table".
uniqueboolfalseAre elements unique (as Java Set)? or not (as Java ArrayList)?
sortFunctionfunctionnilif 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 element)

Add element in the Collection.

If Collection is a Set (unique values) and already contains element, nothing is added.

ParameterTypeDefaultDescription
elementelementType  
Return
int: Number of inserted element: 0 or 1.
Error
if type(element) doesn't match constructor elementType parameter

Collection:addAll(anotherTable)

Add all elements of a table or Collection in this Collection.

ParameterTypeDefaultDescription
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

ParameterTypeDefaultDescription
elementelementType  
Return
bool: true, or nil (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?

ParameterTypeDefaultDescription
anotherTable  A table (native Lua table or Collection:toArray()) or a Collection
Return
bool: 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.

ParameterTypeDefaultDescription
fnfunction A function that accept an element as argument and must return two values:
  • First is the new element value
  • Second is a boolean, true to replace the value in the Collection, nil or false if no replacement to do.
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()

ParameterTypeDefaultDescription
indexnumber  
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.

ParameterTypeDefaultDescription
elementelementType  
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")) --> -1

Collection:isEmpty()

Is this Collection empty?

Return
bool: 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
bool: true, or nil (for false)
Example
Collection:new("string"):isSet() --> false
Collection:new("string", true):isSet() --> 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.

ParameterTypeDefaultDescription
elementelementType  
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")) --> 3
print(c:lastIndexOf("cherry")) --> -1

Collection:remove(elementType element)

Removes the first element of this Collection that equals the given element.

ParameterTypeDefaultDescription
elementelementType  
Return
int: Number of element removed, 0 or 1
Errors
if type(element) doesn't match constructor elementType parameter
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

ParameterTypeDefaultDescription
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

ParameterTypeDefaultDescription
indexnumber 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.

ParameterTypeDefaultDescription
idxnumber 1 <= idx <= size()
newElementelementType  
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.

ParameterTypeDefaultDescription
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)
--> 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:

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, bool inclusive)

Returns a partial copy of this Collection, with elements less (or equal, if inclusive = true) than the given element.

ParameterTypeDefaultDescription
elementelementType  
inclusiveboolfalseInclude 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, bool fromInclusive, elementType to, bool toInclusive)

Returns a partial copy of this Collection, with elements between from and to.

ParameterTypeDefaultDescription
fromelementType  
fromInclusivebooltrueInclude from in result?
toelementType  
toInclusiveboolfalseInclude to in result ?
Return
Collection: A new Collection with same properties, can be empty
Errors
if from >= to
if type(from) or type(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, bool inclusive)

Returns a partial copy of this Collection, with elements greater (or equal, if inclusive = true) than the given element.

ParameterTypeDefaultDescription
elementelementType  
inclusiveboolfalseInclude 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: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.

ParameterTypeDefaultDescription
elementelementType  
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.

ParameterTypeDefaultDescription
elementelementType  
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.

ParameterTypeDefaultDescription
elementelementType  
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.

ParameterTypeDefaultDescription
elementelementType  
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.

ParameterTypeDefaultDescription
iteratorNamestringnil 
See
Collection:hasNext
Collection:next
Collection:reverseIterator

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.

ParameterTypeDefaultDescription
iteratorNamestringnil 
See
Collection:hasNext
Collection:next
Collection:iterator

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.

ParameterTypeDefaultDescription
iteratorNamestringnil 
Return
bool: 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.

ParameterTypeDefaultDescription
iteratorNamestringnil 
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.

See
Collection:debug
LOG_LEVEL

Collection:debug()

Debug a structure of this Collection in console, only if LOG_LEVEL = LOG_LEVEL_DEBUG.

See
Collection:print
LOG_LEVEL