Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested tables and numerical keys in Lua

I'm not sure if this is possible due to the numerical indices, but hopefully someone can point me in the right direction.

Given the table of:

t = { 13, 200, 12, 15, 23 }

how can I nest a table using the numbers?

t["200"] = {"stuff", "more stuff", "even more stuff"}

doesn't seem to work, as it'll create a position 200 and fill in the empty cells with null. I'd add a letter as a suffix/prefix, but the problem comes trying to sort the table numerically. Is this even possible, or am I stuck with a different method? Thanks!

Slight edit due to a realisation:

t["200"] = {"stuff", "more stuff", "even more stuff"}

actually creates a key of "200", whereas:

t[200] = {"stuff", "more stuff", "even more stuff"}

creates the index 200 with everything else null.

like image 457
Josh Avatar asked Jan 19 '23 10:01

Josh


1 Answers

First, DeadMG is correct; you used a string rather than a numerical index. However, even if you did use a number index, it wouldn't help.

If you do this:

someTable = {"value1", "value2", {"value3a", "value3b"}};
someTable[50] = {"value50a", "value50b"};

The length of the table, #someTable, will still be 3. Why? Because Lua defines arrays in a table based on contiguous elements. Remember: you can access any element of any table; they are all conceptually filled with nil until you give them an actual value.

Lua defines length for a table as the number of values in a table if you start counting from numerical index 1 until you reach the first nil value. Since someTable[4] is nil, the length is 3.

If you want to insert a new element at the end of an array table, then you can do this:

someTable[#someTable + 1] = "newValue";

The value can itself be a table:

someTable[#someTable + 1] = {"newValuea", "newValueb"};

If you're just asking how to access a nested table, that's simple, and it has nothing to do with the keys you use.

There is nothing special about nested tables. Tables are values, and table entries can be any value, including other tables.

If you have a table, and want to walk the array entries in it, you use this:

local aTable = {"first", "second", "third", ...}
for i, value in ipairs(aTable) do
    --`value` contains the entries in the table.
end

A nested table is no different; it is simply a matter of getting the table.

local nestedTable = { "first", "second", "third", ...}
nestedTable[#nestedTable + 1] = {"newFirst", "newSecond", ...}
local aTable = nestedTable[#nestedTable];
for i, value in ipairs(aTable) do
    --`value` contains the entries in the table.
end

Or you could just do ipairs(nestedTable[#nestedTable]). Note that the particular key used here (an integer value) is entirely unimportant. That key could have been a string, a floating-point number, another table, some user-data, etc. It doesn't matter.

Note also that we use ipairs because we only want to iterate over the array members of the table. The length of the array is defined above. If we wanted to loop over every member of the table, we would use pairs instead of ipairs. Of course, pairs does an unordered search, so it is not guaranteed to be in array order.

If you want to recursively find every element in a nested table, you can do this:

local function RecursiveSearch(aTable)
    for key, value in pairs(aTable) do --unordered search
        if(type(value) == "table") then
            RecursiveSearch(value)
        else
            --Do something with this.
        end
    end
end

Note that the above can do an infinite loop, since it is possible for a table to have circular references:

local tableA = {}
local tableB = {tableA}
local tableA[1] = tableB
RecursiveSearch(tableA) --Infinite loop.
like image 83
Nicol Bolas Avatar answered Jan 25 '23 14:01

Nicol Bolas