lolalek
lolalek

Reputation: 3

How to redefine values in inner tables?

Basically, scan the entire table for values of type say booleans for example and change them into a string, must work for inner tables and dictionaries...

local Table = {
  String = "abc",
  Number = 123,
  Boolean = true,
  InnerTable = {
     Boolean2 = false,
     InnerInnerTable = {
        Boolean3 = true,
        InnerInnerInnerTable = {
           -- And so on...
        }
     }
  }
}

In this example I want to change every boolean in the table to a string like "true" but without knowing what the table looks like, what I need is a function for any table parsed to be edited (dictionary or not). I couldn't accomplish this with a for loop or custom recursive functions so I need help.

Upvotes: 0

Views: 58

Answers (1)

Luatic
Luatic

Reputation: 11171

What you need is a simple traversal of the table structure which maps booleans to strings. This can be implemented recursively as follows:

local function deep_bool_to_string(tab)
    for k, v in pairs(tab) do
        if type(v) == "boolean" then
            tab[k] = tostring(v)
        elseif type(v) == "table" then
            deep_bool_to_string(v)
        end
    end
end

Usage in your example: deep_bool_to_string(Table). Mutates Table.

Note that this only recursively dives into values, not keys of tables, as the latter isn't well defined: Should {["true"] = 1, [true] = 2} become {["true"] = 1} or {["true"] = 2}?

In its current form, this function has two limitations:

  1. A circular table structure will cause it to overflow the stack.
  2. A too deeply nested table structure may do the same.

(1) can be fixed by keeping track of already converted tables:

local deep_bool_to_string = function(tab)
    local seen = {} -- "Set" of seen tables
    local function convert(t)
        seen[t] = true
        for k, v in pairs(t) do
            if type(v) == "boolean" then
                t[k] = tostring(v)
            elseif type(v) == "table" and not seen[v] then
                convert(v)
            end
        end
    end
    convert(tab)
end

(2) can be fixed by implementing the traversal using a table-based "stack":

local deep_bool_to_string = function(tab)
    local seen = {[tab] = true} -- "Set" of seen tables
    local to_convert = {tab} -- "Stack" of tables to convert
    repeat
        local t = table.remove(to_convert) -- "pop" from stack
        for k, v in pairs(t) do
            if type(v) == "boolean" then
                t[k] = tostring(v)
            elseif type(v) == "table" and not seen[v] then -- new table found?
                seen[v] = true
                table.insert(to_convert, v) -- "push" on stack
            end
        end
    until #to_convert == 0
end

All these are implementations of depth-first traversals, since they are usually more convenient to write (and more efficient) than breath-first traversals since they use a stack rather than a queue.

Upvotes: 3

Related Questions