Lua - handling length of Lists
When we represent a sparse list using table as we discussed in Lua - Sparse Lists chapter, the standard method to get length of list using # operator may not work properly. To handle such a situation, we can use __len() metamethod. __len(table) is called when # operator is called to get the length of the table/list.
Syntax
__len(table)
where
table represents the current table whose behavior is to be modified.
Example - Problem in length Calculation
# operator tries to get length of a list assuming indexes in contigous order. In case of sparse lists, behavior is not correct as shown below:
main.lua
-- list with non-contigous indexes
local list = {[1]="apple",[3]="banana",[5]="mango"}
-- get length of the list
print(#list)
-- iterate List
for index, value in ipairs(list) do
print(string.format("Index: %s, Value: %s", index, value))
end
-- get unassigned Value
print(list[2])
Output
When we run the above code, we will get the following output−
1 Index: 1, Value: apple nil
As we can see, # is not able to calculate length of list correctly. Even ipairs() iterators stops when it encounters nil or unassigned index.
Example - Solution to correctly calculate length
We can implement __len(table) metamethod to calculate length correctly as shown below−
main.lua
-- list with non-contigous indexes
local list = {[1]="apple",[3]="banana",[5]="mango"}
-- create a metatable for length
local metatableLength = {
__len = function(table)
local items = 0
-- iterate through all entries
for key, _ in pairs(table) do
items = items + 1
end
return items
end
}
-- set the metatable
setmetatable(list, metatableLength)
-- get length of the list
print(#list)
-- iterate List
for key, value in pairs(list) do
print(string.format("Key: %s, Value: %s", key, value))
end
Output
When the above code is built and executed, it produces the following result −
3 Key: 3, Value: banana Key: 1, Value: apple Key: 5, Value: mango
Explanation
local list = {[1]="apple",[3]="banana",[5]="mango"} is used to create a sparse list with non-contigous keys or indexes.
local metatableLength is used to create a meta table with __len() method.
__len = function(table) is the implementation of metamethod __len(table) method.
for key, _ in pairs(table) do is the iteration of table's entries and we're counting the entries and returning the same.
When print(#list) is called then length of list is called via __len() method implementation.
for key, value in pairs(list) do is used to perform navigation on table instead of ipairs() earlier to print key-value pairs of the list.