3

I have been learning Lua for some weeks now and this is my one sticking point time and time again. I have tried to read posts and books on this topic.

I use Lua to query a software monitoring system (Nimsoft) and my data is returned to me in a table.

I will not post the whole output but here is a snippet I think will describe the structure:

The table referance is "h_resp"

root:
      domain:nevil-nmsdom
      robotlist:
        1:
          ssl_mode:0
          os_user2:
          origin:nevil-nmshub
          os_major:UNIX
          ip:192.168.1.58
          os_minor:Linux
          addr:/nevil-nmsdom/nevil-nmshub/nevil-multibot_03
          status:0
          license:1
          last_inst_change:1340754931
          created:1341306789
          offline:0
          last_change:1341306869
          lastupdate:1344522976
          autoremove:0
          os_user1:
          flags:1
          os_description:Linux 2.6.32-5-amd64 #1 SMP Mon Jan 16 16:22:28 UTC 2012 x86_64
          name:nevil-multibot_03
          metric_id:M64FB142FE77606C2E924DD91FFCC3BB4
          device_id:DDFF83AB8CD8BC99B88221524F9320D22
          heartbeat:900
          port:48100
          version:5.52 Dec 29 2011
        2: etc...etc....

I use a tdump function I found on this forum to achieve this.

for k,v in pairs(h_resp) do
print(k.."    ",v)
end

Gives me the top level, I understand this.

domain    nevil-nmsdom
robotlist    table:0x22136a0

Then I try to get the "robotlist"

for k,v in pairs(h_resp.robotlist) do
print(k.."    ",v)
end

As you can see below the indexes are integers and vales another table.

  1    table:0x237e530
  0    table:0x22112a0
  3    table:0x2211460
  2    table:0x2392ee0
  5    table:0x2213e80
  4    table:0x22130e0
  7    table:0x2283b80
  6    table:0x2283ff0
  8    table:0x22a71e0

I also get the fact I can address ONE of these "nested" tables using:

for k,v in pairs(h_resp.robotlist["0"]) do
print(k.."    ",v)
end



  ssl_mode    0
  os_user2    
  origin    network
  os_major    UNIX
  ip    192.168.1.31
  os_minor    Linux
  addr    /nevil-nmsdom/nevil-nmshub/nevil-mysql
  status    0
  ...etc...etc...

To my point, I cannot work out how to ask Lua to iterate over ALL the tables stored in robotlist.

Second I appologise for the long winded email but i am still trying to learn/make sense of this.... I have no previous programming/scripting experiance.

Thanks

Doug Currie
  • 40,708
  • 1
  • 95
  • 119
Teknetik
  • 168
  • 2
  • 15

2 Answers2

9

If you want to print the table list, and then the insides of every table, and then again (much like in inception), the easiest way is to use recursion.

You will need to check the type of the current element of the table you are looking at:

function DeepPrint (e)
    -- if e is a table, we should iterate over its elements
    if type(e) == "table" then
        for k,v in pairs(e) do -- for every element in the table
            print(k)
            DeepPrint(v)       -- recursively repeat the same procedure
        end
    else -- if not, we can just print it
        print(e)
    end
end

You should look at Lua manual, everything is explained there. //EDIT: I should be more clear; there's a section in the manual containing the function very similar to the above.

Doug Currie
  • 40,708
  • 1
  • 95
  • 119
Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135
  • Ah RTFM'd! :D I have treid to read the manual, even bought a book! But an Ultra noob at the moment, I hope the manuals etc will make more sense the more I learn. Thank you for your time in answering my question. – Teknetik Aug 09 '12 at 15:23
  • I am afraid now if I really did **help** you by posting complete answer. Please, please **understand** the code I've posted. – Bartek Banachewicz Aug 09 '12 at 15:24
  • I am trying to understand trust me :) No point just copy pasting... what you explained makes almost perfect sense, however I am not sure the implimentation of LUA I am using has the DeepPrint function (the lua interpriter is bundled with the software) – Teknetik Aug 09 '12 at 15:42
  • That's the point - you have to write it yourself. Lua tends to lack various "standard" functions, for many reasons. Lua Users Wiki is a good information source about "why X isn't in the standard library". It ofter provides reference implementations of said functions. – Bartek Banachewicz Aug 09 '12 at 15:43
  • *facepalm* got it! Its not printing the full table but I am definatly much closer. I'll try work out how to extend this but you have really put me on the right track! – Teknetik Aug 09 '12 at 15:49
  • 1
    @CarlDraper There might be a metatable in your table. `pairs()` does not iterate over keys that are found through a metatable `__index` function or table. Read the [Lua manual](http://www.lua.org/manual/5.1/manual.html#2.8) if you don't know what I'm talking about :) – dualed Aug 10 '12 at 11:04
  • Ah, I forgot about that, nice addition @dualed! – Bartek Banachewicz Aug 10 '12 at 11:05
  • Thanks for the help on this one. I needed to make a change to the order but ultimately led me to understanding how nested iterations work in lua. – Quinlayen Jul 30 '20 at 00:35
0

@Bartek Banachewicz 's answer helped me greatly. I did have to make changes to the order of the code for it to work however. My code was obviously different from below, but using the same idea as above this worked for me.

Note I needed to move the if-else block inside the iteration block and check type v.

function DeepPrint (e)
-- if e is a table, we should iterate over its elements
    for k,v in pairs(e) do -- for every element in the table
        if type(v) == "table" then
          print(k)
          DeepPrint(v)       -- recursively repeat the same procedure
        else -- if not, we can just print it
          //EDIT: print(v .. k)
        end
    end
end

Thank you for the guidance

Quinlayen
  • 52
  • 1
  • 2
  • 8
  • This does not make any sense; why did you move the type check inside of the loop? The original code works for any table (any object, even), but this code fails to work correctly when given an array, or when given a table with array values (e.g. will fail for `{ x = { 1, 2 }, y = { 3, 4 } }`). It fails catastrophically when given anything other than a table as input. What problem were you trying to solve by moving the check? – ad absurdum Jul 30 '20 at 02:32
  • Actually you are correct. In my code on line 8, I didn't print(e) but print(tostring(k) .. ":" .. tostring(v)). I cannot explain why at this point, however I was not able to obtain any result using the code as presented before; it simply sat in an infinite loop. After changing the order I received the results I was searching for. I will need to look further to help understand why. – Quinlayen Jul 30 '20 at 03:59
  • Here is an example of the json I am traversing. It is taken from fitibit. `{"sleep":[{"dateOfSleep":"2019-11-30","duration":16620000,"efficiency":96}]}`. Using a simple pairs iteration I was able to receive `sleep:table:(memory address)`. Using the original presented recursive function I didnt receive a result at all. I decided to begin the traversal first and then recursively reach the 2nd table. Using this method that I listed worked for me and gave me the results I sought. – Quinlayen Jul 30 '20 at 04:16