If you want to run a for
loop, it would look a little something like this: for i, v in pairs(table) do end
, But when should I use ipairs()
rather than pairs()
in a for
loop?
The difference is that ipairs()
will not go through nil
values and stop the for loop after that. As tested in the code sample below.
local t = {"a", nil, "c"}
for i, v in ipairs(t) do
print(i, v) -- 1 a only
end
ipairs
will also iterate through the passed array in order. The order that pairs
iterates in is undefined.
ipairs
can be written in Lua as:
local function inext(tab, index)
index = index + 1
local value = tab[index]
if value ~= nil then
return index, value
end
end
local function ipairs(tab)
return inext, tab, 0
end
pairs
can be written in Lua as:
local function pairs(tab)
return next, tab, nil
end
next
is a primitive function in Lua that takes a table and key and returns the next key-value pair of that table.
ipairs()
will only work on numerical indexes, it’s mainly built for arrays though however I’d recommend using a numerical for loop over a generic due to the micro-optomisation.
Undefined according to the doc, but the behavior in Lua 5.1.4 is to iterate the array part of the table in order, you don’t have to go back and change your pairs code worrying that it’s subtly broken somehow if you do use pairs expecting the array part to be in order.
The only time it makes sense to use ipairs
is if you have a mixed table and need to scan through the numerical indices. However, I would argue that mixed tables can be avoided & are bad design in most cases.
That’s not technically correct though. If you’re following the Lua docs word for word, then if you care about the order of iteration you have to use ipairs
, even if the table isn’t mixed. Thanks to: Lua 5.1 Reference Manual
The order in which the indices are enumerated is not specified, even for numeric indices . (To traverse a table in numeric order, use a numerical for or the
ipairs
function.)
I’ve found some obscure cases where pairs
does not iterate over a table with ordered gapless integer keys in order but ipairs
(as it never actually cares about the array or dictionary part of the table) does:
local array = {[1] = "a", [2] = "b", [3] = "c", [4] = "d"}
for key, value in pairs(array) do
print(key, value) --> unordered
end
for key, value in ipairs(array) do
print(key, value) --> ordered
end
Is this because the table is constructed in such a way (with the dictionary style) that some (or all) key-value pairs are not added to the array part of the table? This seems like the case as refreshing(?) the table by inserting a new pair makes pairs iterate in order:
array[5] = "e"
for key, value in pairs(array) do
print(key, value) --> ordered
end
I would like to point out that in Roblox’s implementation of Lua, ipairs is very slightly slower than pairs. That shouldn’t be the case, but unless something has changed in the past year or two, it is. If you care about efficiency, you should use pairs for dictionaries and a standard numeric for loop (for i = 1,#tab) for lists.
It works that way because using the [key] = value
syntax, you’re directly inserting into the hash part of the table. Lua doesn’t do any special extra check in that case to see whether the key you’re inserting is actually an integer which could go into the array part, it’s just inserting an arbitrary key into the hash part.
As long as you only ever use array operations (table.insert / remove, or manually inserting at the end), then it will preserve ordered behavior.
Well then I’ve got a lot of code to fix
Thank you. I just finished updating Studio and I can verify that it still happens, however.
local t = {} for i=1,100000000 do t[i]=i end local s=tick() for i,v in ipairs(t) do end local e = tick() print(e-s)
6.904 ipairs
local t = {} for i=1,100000000 do t[i]=i end local s=tick() for i,v in pairs(t) do end local e = tick() print(e-s)
1.388 pairs
local t = {} for i=1,100000000 do t[i]=i end local s=tick() for i = 1,#t do end local e = tick() print(e-s)
1.180 numeric loop
Have you tried this in a live game? I’m fairly certain ipairs
had been greatly boosted.
I feel like this is something you can ignore. Realistically you are never really going to iterate over big tables in this mannerism. As well, ipairs saw a significant speed increase with Luau; the speed increase benchmarks as noted in RDC had around a 4 for pairs and 6 for ipairs.
I encourage you to try other tests if you’re worrying about speed (which you really shouldn’t be at all). Smaller tables, more practical scenarios, so on.
Ran your tests again, and they seem to be fairly consistent within a certain margin of error.
The ipairs loop returned:
7.2337448596954
The pairs loop returned:
0.90113949775696
The numeric loop returned:
0.51699042320251 (I actually tested this one a couple times, though thats because of how fast it was, it was always within a margin of .1)
However running these functions almost made my studio crash, so i didn’t test them beyond one time. Interesting thing to note here is that the numeric loop was twice as fast for me as it appeared to have been for you.
Again i do think its important to note based on what was previously said by others, this is a very fringe scenario, the performance difference might be negligible in normal workloads.