Tables can contain values indexed against pretty much any data type. Say you define a value against myTable[1]; the index is 1, and that's a number. Say you define against myTable["user"]; the index (or "key") is "user", and that's a string. You can also use other tables, functions, etc as keys - whatever you like, really, though numbers and strings are the two most common types.
Numeric indexes are treated a bit differently to other types. On the "back end", a table using them is treated as a conventional array. There are functions available which can sort or tell you how many such values exist in your table, for example. Arrays are fairly memory efficient, and it's easy to get values out in a certain order.
Other key types are placed in your table by way of a hash map - the key is hashed, and the resulting number is used to place the value in memory somewhere. This is what allows you to use "any" data type as a key (if you can hash it, it'll work). It also allows you to find data in your table very quickly (as you can put things in using their names - as strings - rather than trying to keep track of which numbers relate to the data you're interested in). However, because the hashes don't bear much resemblance to the original keys, the order in which the data is stored in memory is unpredictable. You also lose access to those handy-dandy functions arrays have for measuring how much data is in your table, and you certainly can't sort them.
So: tables allow you to treat them as arrays, or as hash-maps. And you can treat the one table as
both, if you like.
So: pairs and ipairs.
ipairs only pays attention to your numerically indexed keys, and will always pull them out in order from 1 to whatever. It'll stop as soon as it fails to find lastKey+1. For eg:
myTable = {["boo"] = 34, 234, ["cabbage"] = 4, 324, nil, ["asdf"] = 423, 4}
for key, value in ipairs(myTable) do
print(key..": "..value)
end
You'll get:
1: 234
2: 324
The non-numeric keys get ignored, and all keys after the one set to nil get ignored.
Now with pairs:
myTable = {["boo"] = 34, 234, ["cabbage"] = 4, 324, nil, ["asdf"] = 423, 4}
for key, value in pairs(myTable) do
print(key..": "..value)
end
… you might get:
1: 234
2: 324
4: 4
asdf: 423
cabbage: 4
boo: 34
The non-numeric keys come out in an unpredictable order. The nil-index doesn't prevent it running through the whole table. Numeric keys will generally come out in order, but this may not be guaranteed with all Lua interpreters.
In short:
Use ipairs if you're only using numeric indexes and have no "gaps" in your table. It'll execute faster.
Use pairs if you're using other key types, maybe have gaps, and don't care about order.
If you wanna use non-numeric keys and care about order, use a numerically indexed table to keep track of what's in your string-indexed table. Eg:
local myTable = {["a"] = "hello", ["b"] = "to", ["c"] = "you"}
local myTOC = {"a", "b", "c"}
for key, value in ipairs(myTOC) do
print(myTable[value])
end