lualua-tablemetatable

Editing multidimensional table with uncertain dimensions in Lua


I want to be able to access and edit values in a user-generated table, that can have any number of dimensions.

Say, for this nested table,

table = {
    '1',
    {
        '2.1',
        '2.2'
    },
    {
        {
            '3.1.1',
            '3.1.2'
        },
        '3.2'
    },
}

I would have another table that contains a location for the needed data,

loc = {3, 1, 2}

Ideally, what I'd want is to be able to not only access but edit the values in the table, similar to using table[3][1][2] but by utilizing the loc table,

print(table[loc[1]][loc[2]][loc[3]]) --returns 3.1.2
print(table[loc]) --hypothetically something like this that takes each indexed member of the table in order

I also want to be able to edit this table.

table[loc] = {'3.1.2.1', '3.1.2.2'}

I need to be able to edit the global table, so cannot use the methods listed in this reddit thread, and haven't been able to find the right way to use metatables for this yet. I appreciate the help, thanks.


Solution

  • I think you could simply write an additional function for this purpose.

    function TreeGetValue (Tree, Location)
    
      local CorrectTree = true
      local Index       = 1
      local Dimensions  = #Location
      local SubTable    = Tree
      local Value
    
      -- Find the most deep table according to location
      while (CorrectTree and (Index < Dimensions)) do
        local IndexedValue = SubTable[Location[Index]]
        if (type(IndexedValue) == "table") then
          SubTable = IndexedValue
          Index    = Index + 1
        else
          CorrectTree = false
        end
      end
    
      -- Get the last value, regarless of the type
      if CorrectTree then
        Value = SubTable[Location[Index]]
      end
      
      return Value
    end
    

    Here, we assume that the tree is well-formatted as the beginning. If we find any problem we set the flag CorrectTree to false in order to stop immediately.

    We need to make sure we have a table at every dimension in order index a value from.

    > TreeGetValue(table, loc)
    3.1.2
    

    Obviously, it's also easy to to write the set function:

    function TreeSetValue (Tree, Location, NewValue)
    
      local Index      = 1
      local Dimensions = #Location
      local SubTable   = Tree
    
      -- Find the most deep table according to location
      while (Index < Dimensions) do
        local IndexedValue = SubTable[Location[Index]]
    
        -- Create a new sub-table if necessary
        if (IndexedValue == nil) then
          IndexedValue = {}
          SubTable[Location[Index]] = IndexedValue
        end
    
        SubTable = IndexedValue
        Index    = Index + 1
      end
    
      -- Set or replace the previous value
      SubTable[Location[Index]] = NewValue
    end
    

    And then to test it with your test data:

    > TreeGetValue(table, loc)
    3.1.2
    > TreeSetValue(table, loc, "NEW-VALUE")
    > TreeGetValue(table, loc)
    NEW-VALUE