In tables vs ipairs(table)

Is there a difference between for i,v in tables do end and for i,v in ipairs(tables)
I know the latter is the same as pairs but what about ipairs? Does it do the same as ipairs or is ipairs better for predictable arrays and chronological order?

1 Like

Traditionally, pairs allows you to traverse through dictionaries (and arrays if I remember correctly), while ipairs worked only with arrays.

You don’t have to worry about that in Luau however - you can omit out pairs and ipairs and your generic for loops will still work fine - if anything, it’s marginally faster than using those two.

2 Likes

Yes, there is a difference.

pairs is a generic iterator function that iterates over all key-value pairs in a table.

  • It does not guarantee any specific order of iteration. The order in which pairs are traversed may be arbitrary.
  • It is suitable for tables where the order of elements doesn’t matter, such as when using string keys.
local myTable = {a = 1, b = 2, c = 3}

for key, value in pairs(myTable) do
    print(key, value)
end

ipairs is specifically designed for arrays where the keys are sequential integers starting from 1.

  • It guarantees a predictable order based on the numerical indices of the array.
  • It stops iteration when it encounters the first nil value in the array.
local myArray = {10, 20, 30, 40}

for index, value in ipairs(myArray) do
    print(index, value)
end

In summary, ipairs is best suited for arrays where you want to iterate over elements in a predictable and chronological order. If the order of elements doesn’t matter or if you’re dealing with tables where keys are not sequential integers, then you can use pairs.

1 Like

Basically, pairs() iterates through a Dictionary, not an array. And ipairs() iterates through an array, not a Dictionary.

Imagine that you have a script in ServerScriptService. Then you create a table containing strings and numbers:

local RandomTable = {
 "Sherman", 38,
 "Cake", "ZeroFiveIDK", 91
}

That is an array. An array contains strings, numbers and/or booleans. If you want to get the array’s content you would use a for loop. Like this:

for index, value in ipairs(RandomTable) do
    print(value)
end

Did you see that I used ipairs()? It’s because the RandomTable array only contains strings and numbers. So it is an array.

But what happens when you have something like this:

local PersonInfo = {
 ShermanName = "UltraSecretName",
 ShermanAge = 84,
 MyFriendsName = "IHaveNoFriends",
 MyFriendsAge = 2
}

THAT’S a DICTIONARY!!! :smiley: :smiley: :smiley:
So if you want to get the Dictionary content you would use pairs():

for index, value in pairs(PersonInfo) do
    print(value)
end

Really, you don’t need to use ipairs() or pairs() anymore, you can just do:

local RandomTable = {
 "Sherman", 38,
 "Cake", "ZeroFiveIDK", 91
}

local PersonInfo = {
 ShermanName = "UltraSecretName",
 ShermanAge = 84,
 MyFriendsName = "IHaveNoFriends",
 MyFriendsAge = 2
}

for index, value in RandomTable do
    print(value)
end

task.wait(2)

for index, value in PersonInfo do
    print(value)
end

You see? I didnt use pairs() or ipairs(). I just put the table and :+1: Everything is fine! And if you dont want to use ipairs to go through an array you can do this:

-- I hope this helped byeee!
2 Likes

Generic iteration behaves the same way; it will go through a table in chronological order if possible.

2 Likes

does for i,v in table do end guarantees chronological order like ipairs?

2 Likes

Yes, but a distinction is that GI will still iterate through all values while ipairs will ONLY iterate the array portion of a table

2 Likes

This is wrong.

for x, y in TABLE is the same as for x, y in pairs(TABLE), and the only difference with ipairs is that it will always try to start at index 1 . If that doesn’t exist (reminder, nil is the same as “not existing”), it gives up, because it will never try to iterate over a nil or negative index, whereas the other iterators will skip over nils and… do something with negative indices.

Negative indices, + a hole in the array:

Code:

-- An array, but starts at a negative index.
-- Everything past the 0 key acts like an array defined "normally",
-- with `{value, value, value}`.

local MyTableBeginningWithNegative = {
	[-2] = "a",
	[-1] = "b",
	[0] = "c",
	[1] = nil,
	[2] = "e",
	[3] = "f"
}

-- Generic iteration (`for X, Y in TABLE do`)

warn(`Generic iteration:`)

for Index, Value in MyTableBeginningWithNegative do
	print(`		{Index}: {Value}`)
end

-- `pairs` iteration (`for X, Y in pairs(TABLE) do`)

warn(`Iteration with 'pairs':`)

for Index, Value in pairs(MyTableBeginningWithNegative) do
	print(`		{Index}: {Value}`)
end

-- `ipairs` iteration (`for X, Y in ipairs(TABLE) do`)

warn(`Iteration with 'ipairs':`)

for Index, Value in ipairs(MyTableBeginningWithNegative) do
	print(`		{Index}: {Value}`)
end

Output:

As we can see, tables with negative indices are… kind of janky, with them always being iterated over last despite numerically being before the positive ones. However, ipairs does not iterate at all because the “first index” (1) does not exist (it’s set to nil), and it will give up as soon as it hits a nil value. As well as that, because index 1 is set to nil, it is a hole in the array and the first two loops skip over it.

A normal array, but with a hole:

Code:

local ANormalArrayWithAHole = {
	"T",
	"U",
	"V",
	nil,
	"X",
	"Y",
	"Z"
}

warn(`Starting test with an array that contains a hole.`)

-- Generic iteration (`for X, Y in TABLE do`)

warn(`Generic iteration:`)

for Index, Value in ANormalArrayWithAHole do
	print(`		{Index}: {Value}`)
end

-- `pairs` iteration (`for X, Y in pairs(TABLE) do`)

warn(`Iteration with 'pairs':`)

for Index, Value in pairs(ANormalArrayWithAHole) do
	print(`		{Index}: {Value}`)
end

-- `ipairs` iteration (`for X, Y in ipairs(TABLE) do`)

warn(`Iteration with 'ipairs':`)

for Index, Value in ipairs(ANormalArrayWithAHole) do
	print(`		{Index}: {Value}`)
end

Output:

image

As we can see, index 4 is set to nil, and therefore is a “hole” in the array. Generic iteration and pairs (again, both function identically) skip over the hole, but ipairs stops once it hits it.

I hope that this helps clear up some confusion around these different methods of iteration, but I will say that I have never needed to use ipairs, and you can pretty much always use for X, Y in TABLE without any iterator functions.

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.