ipairs()
and pairs()
are slightly different, as you can see on the manual reference.
A less-technical description could be that:
-
ipairs()
returns index-value pairs and is mostly used for numeric tables.
The non-numeric keys are ignored as a whole, similar to numeric indices less than 1.
In addition, gaps in between the indexes lead to halts.
The ordering is deterministic, by numeric magnitude. -
pairs()
returns key-value pairs and is mostly used for associative tables.
All keys are preserved, but the order is unspecified.
In addition, while pairs()
may be used to get the size of a table (see this other question), using ipairs()
for the same task is unsafe a priori, since it might miss some keys.
The differences between both options is illustrated in the following code fragment.
> u = {}
> u[-1] = "y"
> u[0] = "z"
> u[1] = "a"
> u[3] = "b"
> u[2] = "c"
> u[4] = "d"
> u[6] = "e"
> u["hello"] = "world"
>
> for key, value in ipairs(u) do print(key, value) end
1 a
2 c
3 b
4 d
>
> for key, value in pairs(u) do print(key, value) end
1 a
2 c
3 b
4 d
6 e
0 z
hello world
-1 y
>
As we can see in the example, while all keys appear in the output for pairs()
, some are missing for ipairs()
:
hello
because it is not a numeric key;
-1
and 0
since, despite they are numeric, their value is less than 1, and;
6
given that we implicitly have u[5] = nil
, and finding a nil value while iterating is exactly the ending condition for ipairs()
.
Finally, note that as in your example, when you create a table without specifing any of the keys, e.g., a = {"one", "two", "three"}
, numeric keys starting in 1 are implicitly assigned to each of the values, i.e. the definition is understood as a = { [1] = "one", [2] = "two", [3] = "three" }
.
As a consequence, using pairs()
or ipairs()
is mostly the same in these scenarios, except for the non-guaranteed ordering of pairs()
.