Print statement not executing within ipairs loop

Viewed 85

I have the following table defined which consists of tables defined under a string index as such:

local myTable = {
    ["str-1"] = {
        id = 1,
        value = "val"
    },

    ["str-2"] = {
        id = 2,
        value = "val",
    },

    ["str-3"] = {
        id = 3,
        value = "val",
    }
}

for i, table in ipairs(myTable) do
    print(i)
    print(table)
end

I'm attempting to loop through the contents of the table however the print() statements are not giving an output? I have placed a print statement to print both the current index of the loop and the table at that position.

3 Answers

This is because you are attempting to use an ipairs() loop over an associative array.

Instead, you can use a pairs() loop which supports iteration where the index of a table is associative:

for i, table in pairs(myTable) do
    print(i)
    print(table)
end

A pairs() loop uses a key-value pair and works with associative tables, this also results in iteration not being conducted in order whereas an ipairs() uses an index-value pair, the likes of which can be used on a regular table defined with numerical indexes.

From the Lua Reference Manual: ipairs

ipairs (t)

Returns three values (an iterator function, the table t, and 0) so that the construction

 for i,v in ipairs(t) do body end

will iterate over the key–value pairs (1,t[1]), (2,t[2]), ..., up to the first absent index.

As you see ipairs only works for sequences.

Your table does not have any key value pairs (1,t[1]), (2,t[2]), ... so the generic for loop is terminated immediately.

Use pairs

If t has a metamethod __pairs, calls it with t as argument and returns the first three results from the call.

Otherwise, returns three values: the next function, the table t, and nil, so that the construction

 for k,v in pairs(t) do body end

will iterate over all key–value pairs of table t.

See function next for the caveats of modifying the table during its traversal.

Time to present a version that can do both...

tprint=function(self,...)
local args={...}
local start=args[1]
local stop=args[2]
if type(args[1])=='number' and type(args[2])=='number' then
 for i=start,stop do
  io.write(string.format('%d = %s\n',i,table.concat(self,'',i,i)))
 end
else
 for key,value in pairs(self) do
  io.write(string.format('%s = %s\n',key,value))
 end
end
end

With one table argument it is using pairs()
With table and two numbers it prints out start (first number) and stop (second number).
Example for arg that often starts with key 0

-- Print out only key 0
> tprint(arg,0,0)
0 = /root/lua-5.4.0/src/lua
-- Using pairs()
> tprint(arg)
1 = -i
2 = -e
3 = setmetatable(arg,{__index={code={},concat=table.concat}}); 
0 = /root/lua-5.4.0/src/lua

I am using this as a metamethod for arg as __call or/and __index.tprint.

Related