for a,b in pairs is a common loop.
It's entire syntax is- for a,b in pairs (table) do.
In basic terms, what this does is goes across every value in a table and will reference it as you've put forth in the loop.
I is the number of times it has ran, in a sense.
V is the object it's referring to in the table.
In fact, the reason why the two most common variables for it are i and v, is because they stand for index and value. Indexing how many times it has ran, and running through each value.
Keep in mind you can use any value for i and v; I instinctively use a and b.
Here's an example:
x = {"Hello", "How are you", 666}
for a,b in pairs(x) do
print(b)
end
This would run the loop three times, for each value in the table.
Since it's running three times, each time, referencing bas the value in the table it's running with, and you can print both string values and number values, it will print-
Hello
How are you
666
This is the basis of it.
Now, to answer your question in full, I'll tell you the difference between for a,b in ... pairs, ipairs, and finally, next.
ipairs does the exact same thing as pairs, but with a slight twist to it.
ipairs runs through the table, until it finds a nil value, or a value that is non-existent, if that makes sense. So, if you ran the script I showed you for pairs, but just replaced pairs with ipairs, it would do the exact same thing, however...
Let's give you an example of what ipairs will do when it comes across a nil value.
y = {"Hello","Are you feeling good?",nil,"Yay!"}
for a,b in ipairs(y) do
print(b)
end
... that would print out:
Hello
Are you feeling good?
Why?
Because it's stopping at nil.
It will not print nil, because you can't print a value that isn't there, and will not print "Yay!", either, because it has stopped.
Finally, next.
z = {"A","B","C"}
print(next(z))
This returns...
1
A
It returns both the index and it's associated value.
print(next(z,2))
3
C
Wait. Why C? Isn't it the third value?
Well, logically, yes.
But it counts A as 0, B as 1, and C as 2.
However, if you were to go like this,
print(next(z[2]))
... it would return-
2
B
... because it's directly referring to the second value of the table, and it doesn't have a second argument.
I hope this helped! Good luck; and please consider giving me an upvote!