Nested tables and numerical keys in Lua

23,170

Solution 1

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.

Solution 2

Perhaps it helps to view your assignment like this:

t = { [1] = 13, [2] = 200, [3] = 12, [4] = 15, [5] = 23 }

To change what is currently 200 (namely t[2]), you do:

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

Edit: that results in your table looking like this:

t = { [1] = 13, [2] = {"stuff", "more stuff", "even more stuff"}, [3] = 12, [4] = 15, [5] = 23 }
-- or, equivalent::
t = { 13, {"stuff", "more stuff", "even more stuff"}, 12, 15, 23 }

Solution 3

The trouble is your use of "". Your table t contains a bunch of numbers, and you're entering a string as the key. You want to iterate over the table and do... something that you didn't particularly well define. However, you can't add to a table whilst iterating over it, so you might have to do some funny stuff.

t = { 13, 200, 12, 15, 23 }
newt = {};
for key, value in pairs(t) {
    newt[value] = { }; 
}

This will create a table entry in newt, where the key is a value in the table t, for all values in t.

Share:
23,170
Josh
Author by

Josh

Updated on July 09, 2022

Comments

  • Josh
    Josh almost 2 years

    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.

  • Josh
    Josh almost 13 years
    Okay, following that, how would I call the values? The reason why the numbers are haphazard is they represent different levels of equipment on a MUD I play. So I store the different equipment in each level key. If I want to retrieve that level's equipment, what would I call? newt[level] or t[newt[level]]? Or something else?
  • Josh
    Josh almost 13 years
    I'm not wanting to add a new element, though. I'm wanting to edit an existing element (say, 200 in this case) by making it a nested table. So ideally, I'd want to retrieve that table with t[200] and do a foreach on the inner table in the future.
  • Nicol Bolas
    Nicol Bolas almost 13 years
    @Josh: Your original question was focused on how adding the element 200 to a table caused the entries between the end of the list and element 200 to be filled with "nil". I have added a section to my answer that deals with how to walk nested tables.