The length operator (#) only works on the part of a table where the keys are sequentially indexed from 1 up to some value, without any gaps in the numerical sequence. Remember that all Lua tables are associative arrays (key-value pairs), but for convenience that functionality can be hidden away when creating a table that functions as a classic array. An example:
local t = { "foo", "bar", "defold", "britzl" }
print(t[3]) -- defold
print(#t) -- 4
-- equivalent to the above, and it is what happens "behind the scenes" when the table above is created
-- every value gets an associated numeric key, but still lets the table work as a traditional array with numeric index
local t = { [1] = "foo", [2] = "bar", [3] = "defold", [4] = "britzl" }
print(t[3]) -- defold
print(#t) -- 4
Now if we create a hole in our numerical sequence we break the “contract” we have with the Lua length operator and we get this result instead:
local t = { [1] = "foo", [2] = "bar", [3] = "defold", [4] = "britzl" }
t[3] = nil
print(#t) -- 2, there is now a hole in my sequence and the # operator will work up until the first nil value
In your case you do not have any numeric keys at all. Your Lua table functions not as an array but rather as a map or dictionary with all keys being non-numeric. The length operator will correctly report a length of 0. I’m assuming that the classes
table is static and it will never change? You could duplicate the data in the table and have it both as key value pairs for easy access of the factory url when the class is known and at the same time have an array part that can be used when randomly picking a class. Something like this:
local classes = {}
-- add class both in the "array" part of the table for # operator to work
-- and add class to the "dictionary" part of the table
function add_class(class, url)
classes[#classes + 1] = url
classes[class] = url
end
add_class("tank", "#tank_factory")
add_class("collector", "#collector_factory")
add_class("buggy", "#buggy_factory")
add_class("emp", "#emp_factory")
add_class("constructor", "#constructor_factory")
add_class("rocketlauncher", "#rocketlauncher_factory")
print(#classes) -- 6
print(classes[4]) -- "#emp_factory"
print(classes.collector) -- "#collector_factory"
Or like this:
local classes = {
{ class = "tank", factory = "#tank_factory" },
{ class = "collector", factory = "#collector_factory" },
{ class = "buggy", factory = "#buggy_factory" },
{ class = "emp", factory = "#emp_factory" },
{ class = "constructor", factory = "#constructor_factory" },
{ class = "rocketlauncher", factory = "#rocketlauncher_factory" }
}
-- convert the original data structure to an "array" part with the factory url
-- and a "dictionary" part keyed on class type
for i,v in ipairs(classes) do
classes[v.class] = v.factory
classes[i] = v.factory
end
print(#classes) -- 6
print(classes[4]) -- "#emp_factory"
print(classes.collector) -- "#collector_factory"