Behaviour of looping through tables

Hey there, so I was playing a bit with tables and noticed some behaviour I can’t seem to understand.
So I wanted to ask about it here.

Example1

local TestTable = {}

TestTable[2] = "twoooo"
TestTable[1] = "onee"
TestTable[3] = "three"
TestTable[5] = "fivee"
TestTable[8] = "eight"
TestTable[7] = "seven"

for i,v in pairs(TestTable) do
	print(i)
	print(v)
end

--[[
OUTPUT:
1
onee
2
twoooo
3
three 
5
fivee
7
seven
8
eight
]]

Example2
The only thing changed is that I removed TestTable[2] = “twoooo”

local TestTable = {}
TestTable[1] = "onee"
TestTable[3] = "three"
TestTable[5] = "fivee"
TestTable[8] = "eight"
TestTable[7] = "seven"

for i,v in pairs(TestTable) do
print(i)
print(v)
end

--[[
OUTPUT:
1
onee
5
fivee
8
eight
7
seven
3
three
]]

In Example1, the order in which the table is printed, is in the order of the lowest number to the highest number.

In Example2, the order in which the table is printed, is in a random order. So not from the lowest number to the highest number.

Is there a reason why the order in which the numbers are printed has changed?

1 Like

Basically, when using pairs, the table is not guaranteed to iterate in an ascending order. If you were wanting to get the table to iterate in a guaranteed ascending order, then you will need to use ipairs which will increment in a numerical order until a index is nil, so this means missing the index 2 would cause the the iteration to come to a end.

2 Likes

Hello @speeddecoolste!
This issue is because of the fact that the iterator pairs. It prints a table everything regardless of whether the key is numerical or not.

ipairs on the other hand loop numerically in order. If it ever comes by a nil or a non-numerical key, it does not print that key or anything proceeding after it.

local tab = {}

tab["four"] = 4
tab[1] = "one"
tab[2] = "two"
tab[3] = "three"
tab[5] = "five"

for i, v in pairs(tab) do
	
	print(i, v)
	
end

--[[this prints...
	
	1 one
	2 two
	3 three
	four 4
	5 five
	
--]]

for i, v in ipairs(tab) do
	
	print(i, v)
	
end

--[[however, this ONLY prints...
	
	1 one
	2 two
	3 three
	
--]]

Notice how ipairs did not print the key “four”. In fact, it does not even print anything after it, because as you can see, it did not print key “5”.

You can learn more in this article. It covers pairs and ipairs in the section “Standard Library Iterators”.

I hope that helped you.

1 Like

next isn’t guaranteed to iterate in order.

It should iterate in order for an array, but for other things like a dictionary (or what you’re doing), there isn’t a very clear way to iterate through the table, so it does what it thinks is best.

Adding the elements in the table constructor for the second example fixes the unintended behavior you’re experiencing.

local TestTable = {
    "onee",
    nil,
    "three",
    nil,
    "fivee",
    nil,
    "seven",
    "eight"
}
for i,v in pairs(TestTable) do
    print(i,v)
end

This example makes it much more clear that it should be an array, so it iterates correctly.

When you added the elements with TestTable[x] = value it was likely being added to the hash part of the table instead of the array part.

3 Likes