Help me solve this lua puzzle...printing table contents recursively

I’m trying to make it so that I can print out a table in a way where the output is valid lua code for initializing a table with the same contents. ie:

for

foo = {
    { 6, 1, true },
    { 4, 2, { 5, 1, { 4, 3, "all" } } },
    { 3, 3, "all" },
    { 6, 4, "every2" },
    { 4, 5, "every3" },
    { 2, 6, "every4" },
    { 8, 7, "random" },
    { 9, 8, "long" }
}

running

tprint(foo, "foo")

prints (tabbing/whitespace doesn’t need to be exactly the same)

foo = {
    { 6, 1, true },
    { 4, 2, 
        { 5, 1, 
            { 4, 3, "all" }
        }
    },
    { 3, 3, "all" },
    { 6, 4, "every2" },
    { 4, 5, "every3" },
    { 2, 6, "every4" },
    { 8, 7, "random" },
    { 9, 8, "long" }
}

I have a recursive solution figured out for printing out the values based on indexing, but that only works if the table has been initialized with the same number of contents. Spent more time than I’m willing to admit trying to figure this out, but it’s stumped me. Anyone have the desire to solve this programming puzzle?

My current solution:

foo = {
    { 6, 1, true },
    { 4, 2, { 5, 1, { 4, 3, "all" } } },
    { 3, 3, "all" },
    { 6, 4, "every2" },
    { 4, 5, "every3" },
    { 2, 6, "every4" },
    { 8, 7, "random" },
    { 9, 8, "long" }
}

tprint = function(t, n, _k)
    n = n ~= nil and n or 'n'
    if type(t) == 'table' then
        for k,v in pairs(t) do
            if _k ~= nil then
                k = '\t' .. _k .. '[' .. k .. ']'
                if type(v) == 'table' then
                    -- print(k .. ' is a table')
                end
            else
                k = n .. '[' .. k .. ']'
                -- print(k .. ' is a table')
            end
            tprint(v, n, k)
        end
    else
        t = type(t) == 'string' and '"' .. t .. '"' or t
        print(_k .. ' = ' .. tostring(t))
    end
end

tprint(foo, "foo")

-- outputs
  foo[1][1] = 6
  foo[1][2] = 1
  foo[1][3] = true
  foo[2][1] = 4
  foo[2][2] = 2
    foo[2][3][1] = 5
    foo[2][3][2] = 1
      foo[2][3][3][1] = 4
      foo[2][3][3][2] = 3
      foo[2][3][3][3] = "all"
  foo[3][1] = 3
  foo[3][2] = 3
  foo[3][3] = "all"
  foo[4][1] = 6
  foo[4][2] = 4
  foo[4][3] = "every2"
  foo[5][1] = 4
  foo[5][2] = 5
  foo[5][3] = "every3"
  foo[6][1] = 2
  foo[6][2] = 6
  foo[6][3] = "every4"
  foo[7][1] = 8
  foo[7][2] = 7
  foo[7][3] = "random"
  foo[8][1] = 9
  foo[8][2] = 8
  foo[8][3] = "long"
1 Like

also, this would be a welcome addition to the core library

1 Like

:+1: happy to submit a PR (or whoever solves this can submit one)! I started with what was here: https://github.com/monome/norns/blob/fd2485af8228ab11d111d1283c9b314857fe5d32/lua/lib/tabutil.lua#L9

If this is desired for crow (I know I’d get a lot of use out of it, but this might be less useful for others and not worth the space it takes up to always load), I’d be happy to optimize it down as small as possible to put somewhere in here: https://github.com/monome/crow/tree/master/util

1 Like

just a disclaimer - I don’t really know lua, but I’m a sucker for a programming puzzle

looking at the problem, it struck me as similar to json encoding/serialization, so I took a quick look online for a lua json library
using this https://github.com/rxi/json.lua/blob/master/json.lua library’s encode function, it was pretty straightforward to get something working - you might be able to trim it down for the specific use case too

2 Likes

ah cool, good find, I’ll see if I can tweak and make their thing work.

I also like programming puzzles, but I had to accept defeat and move on from this one :sweat_smile:

1 Like

There are a few edge cases depending on what is in the input table. See this for inspiration:

http://lua-users.org/wiki/TableSerialization

2 Likes

I think this should work for the test data given. It most definitely does not preserve whitespace though that shouldn’t be too much trouble to sort out. It also will not re-escape strings when printing so "This \"is\" a string" will be printed as "This "is" a string" which could definitely cause some issues. I don’t think it would be too tricky to add something to this to iterate over the string and add the \ characters as needed.
This function also adds trailing commas but everything should still work correctly if the goal is to print working lua code.

Function:

tprint = function(table, name)
  local str = name .. '='

  step = function(item)
    if type(item) == 'table' then
      str = str .. '{'
      for i = 1, #item do
        step(item[i])
      end
      str = str .. '},'
    elseif type(item) == 'string' then
      str = str .. '"' .. item .. '",'
    else
      str = str .. tostring(item) .. ','
    end
  end

  step(table)

  -- strip out the final trailing ',' if there is one
  if (str:sub(#str)) == ',' then
    print(str:sub(1, #str - 1))
  else
    print(str)
  end
end

Input:

foo = {
  { 6, 1, true },
  { 4, 2, { 5, 1, { 4, 3, "all" } } },
  { 3, 3, "all" },
  { 6, 4, "every2" },
  { 4, 5, "every3" },
  { 2, 6, "every4" },
  { 8, 7, "random" },
  { 9, 8, "long" }
}

output:

foo={{6,1,true,},{4,2,{5,1,{4,3,"all",},},},{3,3,"all",},{6,4,"every2",},{4,5,"every3",},{2,6,"every4",},{8,7,"random",},{9,8,"long",},}
1 Like

For general debugging I’ve been using inspect - it’s on luarocks, and this is the source: https://github.com/kikito/inspect.lua. It seems to put out valid Lua as far as I’ve noticed - that’s not been a requirement for me.

1 Like

On the other hand, from the README:

This method is not appropriate for saving/restoring tables. It is meant to be used by the programmer mainly while debugging a program.

Make of that what you will…

1 Like

How do you use luarocks stuff w crow/norns?

Not sure you can - but you could presumably just do the install on a laptop and then drop the files into lib with some path edits. That’s a hack though - full Luarocks support would be nice.

1 Like

gotcha was just making sure there wasn’t some thing i was missing