arsy
arsy

Reputation: 169

How can I loop through nested tables in Lua when the nested tables are mixed in with other data types?

I'm trying loop though a very large table in Lua that consists of mixed data types many nested tables. I want to print the entire data table to the console, but I'm having trouble with nested loops. When I do a nested loop to print the next level deep Key Value pairs I get this error bad argument #1 to 'pairs' (table expected, got number) because not all values are tables.

I've tried adding a if type(value) == table then before the nested loop but it never triggers, because type(value) returns userdata whether they are ints, strings or tables.
EDIT: I was wrong, only tables are returned as type userdata

My table looks something like this but hundreds of pairs and can be several nested tables. I have a great built in method printall() with the tool I'm using for this but it only works on the first nested table. I don't have any control over what this table looks like, I'm just playing with a game's data, any help is appreciated.

myTable = {
    key1 = { value1 = "string" },
    key2 = int,
    key3 = {             -- printall() will print all these two as key value pairs
        subKey1 = int, 
        subKey2 = int
    },
    key4 = {
        innerKey1 = { -- printall() returns something like : innerKey1 = <int32_t[]: 0x13e9dcb98>
            nestedValue1 = "string",
            nestedValue2 = "string"
        },
        innerKey2 = { -- printall() returns something like : innerKey2 = <vector<int32_t>[41]: 0x13e9dcbc8>
            nestedValue3 = int,
            nestedValue4 = int
        }
    },
    keyN = "string"
}

My loop

for key, value in pairs(myTable) do
    print(key)
    printall(value)
    for k,v in pairs(value) do
            print(k)
            printall(v)
        end
    end
    print("====")
end

ANSWER : Here is my final version of the function that fixed this, it's slightly modified from the answer Nifim gave to catch edge cases that were breaking it.

function printFullObjectTree(t, tabs)
    local nesting = ""
    for i = 0, tabs, 1 do
        nesting = nesting .. "\t"
    end
    for k, v in pairs(t) do
        if type(v) == "userdata" then     -- all tables in this object are the type `userdata` 
            print(nesting .. k .. " = {")
            printFullObjectTree(v, tabs + 1)
            print(nesting .. "}")
        elseif v == nil then
            print(nesting .. k .. " = nil")
        elseif type(v) == "boolean" then
            print(nesting .. k .. " = " .. string.format("%s", v))
        else
            print(nesting .. k .. " = " .. v)
        end
    end
end

Upvotes: 1

Views: 1059

Answers (1)

Nifim
Nifim

Reputation: 5031

type(value) returns a string representing the type of value

More information on that Here: lua-users.org/wiki/TypeIntrospection

Additionally your example table has int as some of the values for some keys, as this would be nil those keys are essentially not part of the table for my below example i will change each instance of int to a number value.

It would also make sense to recurse if you hit a table rather than making a unknown number of nested loops.

here is an example of working printAll

myTable = {
    key1 = { value1 = "string" },
    key2 = 2,
    key3 = {             -- printall() will print all these two as key value pairs
        subKey1 = 1, 
        subKey2 = 2
    },
    key4 = {
        innerKey1 = { -- printall() returns something like : innerKey1 = <int32_t[]: 0x13e9dcb98>
            nestedValue1 = "string",
            nestedValue2 = "string"
        },
        innerKey2 = { -- printall() returns something like : innerKey2 = <vector<int32_t>[41]: 0x13e9dcbc8>
            nestedValue3 = 3,
            nestedValue4 = 4
        }
    },
    keyN = "string"
}

function printAll(t, tabs)
    local nesting = ""
    for i = 0, tabs, 1 do
        nesting = nesting .. "\t"
    end
    for k, v in pairs(t) do
        if type(v) == "table" then
            print(nesting .. k .. " = {")
            printAll(v, tabs + 1)
            print(nesting .. "}")
        else
            print(nesting .. k .. " = " .. v)
        end
    end
end

print("myTable = {")
printAll(myTable, 0)
print("}")

Upvotes: 2

Related Questions