Can someone explain how the "for loops" work? I know how while loops work though.
Loops are self explanatory. They run the code within itself until a condition is met. For example, a while loop
will only run if the condition it's given is "truthy" ("truthy" meaning true or not nil).
while 1+1 == 2 do...
The condition is 1+1 == 2
. Since that condition is true, the code loops until that condition becomes false.
For loops are loops that will only loop for a certain number of turns or "iterations". The for loop
will keep looping for each iterator it needs to run through. When you write a for loop
the iterator goes in between the for
and do
. You set the iterator to a number of steps or turns the loop must go through as if it's a variable.
for iterator = 1,10 do --code end
This loop will start counting from the number 1 since we stated that the iterator should start equal to 1. Each loop, the iterator will add 1 to itself. It'll stop when it hits 10 turns or loops like we stated (The loop stops when the iterator is greater or equal to the ending number, if that makes sense). The iterator is set like this: starting number, ending number
. The loop we set in the example will loop a total of 10 times. The iterator will be equal to 1 and count up to 10 by 1 a total of 10 times.
Iterators seem very similar to regular old variables... Is it possible to use them like a variable? The answer is yes! The iterator can be used like a variable within the loop so you can see what "turn" the loop is on.
for iterator = 1,10 do print("Counting up: "..iterator) end
The output will count from 1 to 10. It's important to note that the variable is a local one, and cannot be used outside of the loop, only within it.
Until this point, the iterator always added 1 to itself. What if we wanted the loops to count a different way? The third expression is used to set the increment that the iterator changes by. When left blank, it's 1 by default. We can change the third expression to a negative 1, for example, and swap the location of the starting and ending value to have a loop that counts from 10 to 1.
for iterator = 10,1,-1 do print("Counting down: "..iterator) end
The output will count from 10 to 1. It's important to note that these numbers do not need to be integers. You can have a loop count up by 0.5 or loop until the loop reaches turn 1.25.
A for loop will loop for a certain number of iterations. This is useful, especially when we have to deal with tables. We can tell a for loop to loop through each item in a table. This is called a Generic For Loop
instead of a Numeric For Loop
since we aren't setting how many times the loop must run for.
local days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
This is the table we will be looping through. The following code will not include that table, but just pretend that it is there. We will be using the pairs
function to go through the table and pair each item inside of that table with its place in the table. Example: Sunday > 1, Monday > 2, etc... The following code will loop through the table and give us a "key" and value for every value inside of this table. We can add or remove things from this table and the loop will still work just fine since we aren't manually setting how many times this loop will be looping for. We are simply telling the loop to go through every value inside of the table:
for i,v in pairs(days) do print(v.." is day "..i.." in the week.") end
You can run that code and see what it outputs for yourself (don't forget to include the table from earlier as well). The i
is just shorthand for iterator and v
is shorthand for value. So i
will give us what place the item is inside of the table and v
will be that item itself.
If you're curious about the difference between pairs
, ipairs
and next
, you can check out my other answer here.
The answer above is great however I felt that generic for loops weren't explained well enough. While the example with pairs/ipairs/next
are the most generic (heh) how generic for loops actually work is not explained. So here i am
A generic for loop lets to go through all the return values of the given iterator function. The format of a generic for loop goes
for variables in iterator, invariant, initial_arg do end
And it keeps calling iterator(invariant, next_arg)
until iterator
returns nil. This is why idioms like
for k, v in pairs(t) do end
work because pairs
actually is just
function pairs(t) return next, t, nil end
so when you call pairs(t)
iterator
is next
and invariant
is t
since that first argument is constant.
Here is an example
local function iterator(t, i) -- real iterator i = i - 1 local v = t[i] if v ~= nil then return i, v end return nil end local function reverse_ipairs(t) return iterator, t, #t + 1 end for i, v in reverse_ipairs({ "a" ,"b", "c" }) do -- same as for i, v in iterator, { "a", "b", "c" }, 4 do print(i, v) end
reverse_ipairs
, like pairs
, ipairs
, and string.gmatch
, is an iterator factory since it returns the iterator function.