Using the for in loop

From GMod Wiki

Revision as of 15:31, 10 February 2011 by garry :D (Talk | contribs)
Jump to: navigation, search

Now you should be fairly comfortable with scripting in lua. This is the next trick I'll teach you to use. The for in loop is like the for loop you know already.

If you recall, a for loop works using numbers:

 
for i=1,20 do
	Msg("We're on loop number "..i.."\n")
end
 

That type of loop just:
1. Sets i to 1
2. Runs the code in the block below
3. Increases i by 1
4. If i isn't over 20 yet, go back to step 2.

However, the normal for loop has weaknesses. It can only loop with numbers. The next type of loop you'll learn about is the for in loop. The for in loop is used entirely for looping through every slot in a table.

If you recall, back in the for loop lesson I said you could do the for loop to loop through a table:

 
myTable={}
myTable[1]="Jeff"
myTable[2]="Josh"
myTable[3]="Alan"
myTable[4]="Ryan"
myTable[5]="Andrew"
 
for i=1,5 do
	Msg("myTable's "..i.." slot is "..myTable[i].."\n")
end
 

Now this is all fine and great... but, what if I did this?

 
myTable={}
myTable[1] = "Jeff"
myTable[2] = "Josh"
myTable[3] = "Alan"
myTable[4] = "Ryan"
myTable[5] = "Andrew"
myTable["string"] = "Ball"
 
for i=1,5 do
	Msg("myTable's "..i.." slot is "..myTable[i].."\n")
end
 

The for loop will NOT get be able to get the "ball" from the "string" slot in the table! String is text, and the for loop can only loop numbers! If you remember from the tables lesson, I said you can use a string as an index for a table. Now, in certain situations this has advantages (like when copying complex tables, like objects, which I'll get to later).

So, how do you get around this? Well duh, the for in loop.

Here's how a typical for in loop is written:

 
myTable={}
myTable[1] = "It's a number."
myTable["text"] = "It's a string."
 
for k,v in pairs(myTable) do
    Msg("Looping through table... k is "..k..", and v is "..v.."\n")
end
 

Not too difficult, right? Lets dissect this...

The first part of the for loop is the for k,v in pairs(myTable) do line. The for part tells lua you're making a loop.

The next two letters, k and v, are the names of the variables in the loop. If you remember, in the for loop we had one variable, "i". "i" was a number that was increased each time the loop run. In the for in loop, "k" is the slot the loop is on, and v is what's inside of the slot. Take a look back at our code:

 
myTable={}
myTable[1] = "It's a number."
myTable["text"] = "It's a string."
 
for k,v in pairs(myTable) do
	Msg("Looping through table... k is "..k..", and v is "..v.."\n")
end
 

If k is 1, then v is "It's a number.".
If k is "text", then v is "It's a string.".

This is because v is the same thing as myTable<k>. It's just been shortened to save you work.

The next part of that line is the "in" word. This tells lua that you don't want a normal for loop - we're too good for that - we want a for IN loop.

The next line is the "pairs" part. The table you want to loop through is put here, inside of a pairs(). So if you want to loop through myTable, you put pairs(myTable).

Lastly is the "do" statement. It tells lua to run the code block between "do" and "end" for each slot in the table.

The next part is the code block. It will be run for each slot in the table.

Lastly is the end statement. Everything past this is not part of the loop.

One last thing I think I should mention is that "for in" loops don't go in any certain order. It could choose the first one, then the third one, then the second one, and so on. If you're using a for in loop, make sure the order is not important on what you're doing!

So, how's this useful?
Lets say you have a table indexed with strings. Like I mentioned before, you can't use a normal for loop for tables with strings!

 
--List of stuff sorted by name.
teaminfo={}
 
--Remember doing teaminfo.color is the same
--thing as doing teaminfo["color"]
teaminfo.color = "red"
teaminfo.grenadestock = 35
teaminfo.captures = 40
teaminfo.losses = 25
teaminfo.weaponstock = 15
 
Msg("TEAM INFO:\n")
Msg("------------------------\n")
for k,v in pairs(teaminfo) do
	Msg(k..": "..v.."\n")
end
Msg("------------------------\n")
 

The above example would print this in the console:

 
TEAM INFO:
------------------------
color: red
grenadestock: 35
captures: 40
losses: 25
weaponstock: 15
------------------------
 

Here's another example. We covered this before in tables - the table uses numbers, but they're not going in any specific order.

 
myTable={}
myTable[20] = "Hello"
myTable[300] = "What's up?"
myTable[4] = "Going good?"
myTable[19] = "Same here."
 
for k,v in pairs(myTable) do
	Msg("Message ID "..k..": "..v.."\n")
end
 

The above example prints this in the console:

Message ID 20: Hello
Message ID 300: What's up?
Message ID 4: Going good?
Message ID 19: Same here.

So, you might be wondering, why can't we use a normal for loop for this? We could... but, here's the problem. A normal for loop can only go from one number to the next number. Since the biggest ID we have in the table is 300, it would loop 300 times for four messages. Here's an example of what the code would look like:

 
--Note: table.maxn is used to get the highest index of a table or string
--The length of a table depends on what the biggest
--number index is in the table. Since the biggest
--number index in the table is 300, it will loop
--300 times. Talk about crappy coding.
--I'll talk more about this later.
 
myTable={}
myTable[20] = "Hello"
myTable[300] = "What's up?"
myTable[4] = "Going good?"
myTable[19] = "Same here."
 
for i=0,table.maxn(myTable) do
	Msg("Message ID "..i..": "..myTable[i].."\n")
end
 

In this case, using a for in loop is better. The for in loop only loops once for each slot.

Give this a try if you want.

Open notepad and write this. Modify it if you want. This pretty much covers everything we talked about:

 
stringyTable={}
stringyTable.first = "I'm first!"
stringyTable.second = "I'm second!"
stringyTable.third = "I'm third!"
 
 
--This will be 0, because there are no number indexes.
--Because there are no number indexes you can't use a for loop
--to loop through it!
Msg("Stringy table's length is "..table.maxn(stringyTable).."\n")
 
--But you can use a for in loop.
for k,v in pairs(stringyTable) do
	Msg("Stringy table's "..k.." is "..v.."!\n")
end
 
looseTable={}
looseTable[5] = 1
looseTable[15] = 2
looseTable[2] = 4
looseTable[10] = 7
 
--This will say it's 15 long, because the highest number
--index is 15.
Msg("Loose table's length is "..table.maxn(looseTable)..".\n")
 
Msg("Starting normal loop!\n")
 
--Lets try saying a message each time the normal loop counts.
for i=0,table.maxn(looseTable) do
	Msg("Normal loop is on loop #"..i.."\n")
end
 
Msg("Done!\n")
Msg("Starting 'for in' loop!\n")
 
--Now we'll try the for in loop. We'll say a message for each
--slot in the table that is ACTUALLY filled.
for k,v in pairs(looseTable) do
	Msg("Slot number "..k.." is actually filled.\n")
end
Msg("Done!\n")
 

Save this as forin.lua and open it in Garry's Mod. Try it out, and pay attention to the console. Look back at your code, and look at the console.
Compare the console and your code and you'll see how the "for in" loop can be useful compared to the normal for loop.


Yarin Kaul Icon ArrowSquare32 left.png More tricks with conditions

Yarin Kaul Icon ArrowSquare32.png Back to Lua Tutorial Series

Parentheses with arithmetic Yarin Kaul Icon ArrowSquare32 right.png


Personal tools
Namespaces
Variants
Actions
Navigation
Lua Scripting
Functions
Hooks
Toolbox