The generic for is how you traverse every table and stream in Lua.
The generic for loop, for k, v in explist do ... end, calls an iterator function repeatedly until it returns nil.
ipairs(t)walkst[1],t[2], ... in order and stops at the firstnil. Use it for arrays.pairs(t)visits every key in the table, in an unspecified order. Use it for dictionaries, and never rely on the order. To iterate in a fixed order, collect the keys,table.sortthem, then loop.
You must not add new keys to a table while traversing it with pairs (assigning to existing fields, including setting them to nil, is allowed).
Writing your own iterator is easy with a closure: return a function that produces the next value each call and nil when done. Under the hood the generic for accepts three values (an iterator function, an invariant state and a control value), which is how pairs and ipairs avoid allocating closures. Lua 5.4 adds a fourth closing value used with to-be-closed variables.
Iterators make lazy pipelines natural: io.lines(path) returns an iterator over a file's lines and s:gmatch one over pattern matches, so you can process large inputs without building a table first.
Example
local scores = {ana = 90, bo = 72, cy = 85}
local names = {}
for name in pairs(scores) do names[#names + 1] = name end
table.sort(names) -- fixed order
for i, name in ipairs(names) do
print(i, name, scores[name])
end
--> 1 ana 90
--> 2 bo 72
--> 3 cy 85
local function range(n, step)
local i = 0
return function() -- closure iterator
i = i + (step or 1)
if i <= n then return i end
end
end
for x in range(10, 4) do io.write(x, " ") end --> 4 8
print()
for i, v in ipairs({1, 2, nil, 4}) do io.write(v, " ") end --> 1 2
print()Remember
ipairsfor arrays (stops at the first nil),pairsfor all keyspairsorder is unspecified; sort keys when order matters- An iterator is just a function that returns nil when finished
Watch out for
- Adding keys to a table while iterating it with pairs, which is undefined behaviour.