Iterating over the elements of a list is a very common operation.
Known Length Lists
If the number of elements in the list is known, then it is easy to iterate over the elements using a simple numeric for loop:
local x = { "a", "b", "c", "d" }
for i = 1, 4 do
print(i .. ": " .. x[i])
end
which produces the result:
1: a
2: b
3: c
4: d
This can also be used to iterate over list that contain nil values, which (as we will see in a moment) can be problematic when iterating over lists using other methods. Note that because the concatenation operator will not allow a nil value we have to test for nil and replace it with a string "nil":
local x = { "a", "b", nil, "c", "d" }
for i = 1, 5 do
print(i .. ": " .. (x[i] or "nil"))
end
which produces the output:
1: a
2: b
3: nil
4: c
5: d
Unknown Length Lists
When the length of the list is not known we can use the generic for to
iterator over the items in the list. There are two built-in iterator functions, pairs
and
ipairs
. Let's first look at iterating lists using pairs
:
pairs
The pairs
function returns an iterator over key, value pairs from the list. Due to the way that
lists are created with tables, the keys are the indices of each
element of the list, while the values are the element values themselves. Let's take a look:
local x = { "a", "b", "c", "d" }
for i, v in pairs(x) do
print(i .. ": " .. v)
end
which produces the output:
1: a
2: b
3: c
4: d
Let's compare that to the other built-in iterator function, ipairs
:
ipairs
The ipairs
iterator function creates a counter and iterates over the elements of the list,
yielding index, value pairs. Due to the way that lists are created with
tables, this produces the same output that we just saw with
pairs
:
local x = { "a", "b", "c", "d" }
for i, v in ipairs(x) do
print(i .. ": " .. v)
end
with the output:
1: a
2: b
3: c
4: d
While both iterator functions produced the same output, they behave quite differently when there are nil values in the lists:
Be careful when there are nil values in the list, as the results can be a bit unexpected and surprising.
using pairs with nil values
Let's first look at how the pairs
function behaves when there are
nil values in the list:
local x = { "a", "b", nil, "c", "d" }
for i, v in pairs(x) do
print(i .. ": " .. v)
end
with the result:
1: a
2: b
4: c
5: d
Although there are five elements in the list, the pairs
function only yields four of them,
silently skipping the nil element. While this can be a helpful
feature, in some cases we will want to know if there are nil values in
the list and this behavior would prevent that.
Now let's see how the ipairs
function behaves:
using ipairs with nil values
Here we look at the same input again, but with the ipairs
function:
local x = { "a", "b", nil, "c", "d" }
for i, v in ipairs(x) do
print(i .. ": " .. v)
end
which produces somewhat different results:
1: a
2: b
Rather than iterating over each item in the list, the ipairs
function simply stopped iterating
elements when it reached the first nil value. This is rarely expected
behavior, and can lead to some unexpected behavior.
We can learn more about this behavior by examining how the length operator behaves with lists, in the next section.