Difference between revisions of "Lua: Iterators"

From Mario Fan Games Galaxy Wiki
m (actually that pattern was crap)
m
 
(3 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
{{Lua}}
 
{{Lua}}
'''Iterators''' are special constructs that traverse something and perform actions on the individual parts. In [[Lua]], this is often a table or string. They are [[function]]s most often used in conjunction with a generalized '''for''' loop. The two most common iterator functions used in Lua are '''pairs''' and '''ipairs'''; the former iterates through all keys and indexes in a table, while the latter iterates only numerical indexes. Both return the key (or index) and value of the current place in the table.
+
'''Iterators''' are special constructs that traverse something and perform actions on the individual parts. In [[Lua]], this is often a [[Lua: Tables|table]] or [[Lua: Strings|string]]. They are [[function]]s most often used in conjunction with a generalized <tt>for</tt> loop. The two most common iterator functions used in Lua are <tt>pairs</tt> and <tt>ipairs</tt>; the former iterates through all keys and indexes in a table, while the latter iterates only numerical indexes. Both return the key (or index) and value of the current place in the table.
  
 
<source lang="lua" enclose="div">t = {1, 2, 3, 4, a = "test", b = "what", c = "more", d = "hello", 5, 6}
 
<source lang="lua" enclose="div">t = {1, 2, 3, 4, a = "test", b = "what", c = "more", d = "hello", 5, 6}
Line 11: Line 11:
 
end</source>
 
end</source>
  
You'll notice that '''ipairs''' block is effectively equivalent to this '''for''' loop:
+
You'll notice that <tt>ipairs</tt> block is effectively equivalent to this <tt>for</tt> loop:
 
<source lang="lua" enclose="div">for i = 1, #t do
 
<source lang="lua" enclose="div">for i = 1, #t do
 
   print(i, t[i])
 
   print(i, t[i])
 
end</source>
 
end</source>
However, there are some small differences in how each of those handle nil values, but for most purposes they are interchangeable.
+
However, there are some small differences in how each of those handle <tt>[[Lua: Nil|nil]]</tt> values, but for most purposes they are interchangeable.
  
One thing you may notice is that the printout of '''pairs''' is not necessarily in the same order the table was defined. You can't rely on it to give you information in a predictable order; according to the Lua manual, not even numerical indices are guaranteed to be returned in order (as they are with '''ipairs'''). Obviously, you'll want to be careful when using '''pairs''' (or '''next''', which is the function '''pairs''' actually uses to get the values).
+
One thing you may notice is that the printout of <tt>pairs</tt> is not necessarily in the same order the table was defined. You can't rely on it to give you information in a predictable order; according to the Lua manual, not even numerical indices are guaranteed to be returned in order (as they are with <tt>ipairs</tt>). Obviously, you'll want to be careful when using <tt>pairs</tt> (or <tt>next</tt>, which is the function <tt>pairs</tt> actually uses to get the values).
  
Another useful iterator is found in the '''string''' library: '''gmatch'''. '''gmatch''' allows you to apply a [[Lua: Patterns|pattern]] over a string repeatedly until the pattern no longer matches anything. Of course, it returns the match if there is one. The following usage will separate a list of comma-separated values:
+
Another useful iterator is found in the <tt>string</tt> library: <tt>gmatch</tt>. <tt>gmatch</tt> allows you to apply a [[Lua: Patterns|pattern]] over a string repeatedly until the pattern no longer matches anything. Of course, it returns the matches if there are any. The following usage will separate a list of comma-separated values:
  
 
<source lang="lua" enclose="div">s = "a, b, c e, d"
 
<source lang="lua" enclose="div">s = "a, b, c e, d"
Line 29: Line 29:
 
-- a
 
-- a
 
-- b
 
-- b
-- c
+
-- c e
 
-- d</source>
 
-- d</source>
 +
 +
It is also possible to define your own iterators, which is particularly useful if you use tables to implement other data structures such as linked lists. As a simple example, we will define an iterator called <tt>twos</tt>, which works similar to <tt>ipairs</tt>; however, instead of returning an index number it returns pairs of numbers in a table. In this implementation there is no "overlap" in the pairs, so {1, 2, 3, 4} returns (1, 2) (3, 4) and not (1, 2) (2, 3) (3, 4).
 +
 +
<source lang="lua" enclose="div">twos = function (table)
 +
local index = 0
 +
local previous = 0
 +
return function ()
 +
index = index + 2
 +
previous = table[index - 1]
 +
if previous ~= nil then
 +
return previous, table[index]
 +
else
 +
return
 +
end
 +
end
 +
end
 +
 +
t = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110}
 +
 +
for v1, v2 in twos(t) do
 +
print(v1, v2)
 +
end</source>
 +
In order to signal the <tt>for</tt> expression to stop iterating, we need to return <tt>nil</tt> as the first result.

Latest revision as of 07:52, 5 December 2009

Lua
Lua.gif
Basics
Intermediate
Advanced
XLua
Add to this template
 Standardwikimessagebox.png This article assumes the use of Lua 5.1.

Information may not be accurate or may need revision if you are using a different version.

Iterators are special constructs that traverse something and perform actions on the individual parts. In Lua, this is often a table or string. They are functions most often used in conjunction with a generalized for loop. The two most common iterator functions used in Lua are pairs and ipairs; the former iterates through all keys and indexes in a table, while the latter iterates only numerical indexes. Both return the key (or index) and value of the current place in the table.

t = {1, 2, 3, 4, a = "test", b = "what", c = "more", d = "hello", 5, 6}
for k, v in pairs(t) do
    print(k, v)
end
print("-----")
for i, v in ipairs(t) do
    print(i, v)
end

You'll notice that ipairs block is effectively equivalent to this for loop:

for i = 1, #t do
   print(i, t[i])
end

However, there are some small differences in how each of those handle nil values, but for most purposes they are interchangeable.

One thing you may notice is that the printout of pairs is not necessarily in the same order the table was defined. You can't rely on it to give you information in a predictable order; according to the Lua manual, not even numerical indices are guaranteed to be returned in order (as they are with ipairs). Obviously, you'll want to be careful when using pairs (or next, which is the function pairs actually uses to get the values).

Another useful iterator is found in the string library: gmatch. gmatch allows you to apply a pattern over a string repeatedly until the pattern no longer matches anything. Of course, it returns the matches if there are any. The following usage will separate a list of comma-separated values:

s = "a, b, c e, d"

for p in s:gmatch("%s*([^%,]+)%s*") do
   print(p)
end
-- prints:
-- a
-- b
-- c e
-- d

It is also possible to define your own iterators, which is particularly useful if you use tables to implement other data structures such as linked lists. As a simple example, we will define an iterator called twos, which works similar to ipairs; however, instead of returning an index number it returns pairs of numbers in a table. In this implementation there is no "overlap" in the pairs, so {1, 2, 3, 4} returns (1, 2) (3, 4) and not (1, 2) (2, 3) (3, 4).

twos = function (table)
	local index = 0
	local previous = 0
	return function ()
		index = index + 2
		previous = table[index - 1]
		if previous ~= nil then
			return previous, table[index]
		else
			return
		end
	end
end

t = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110}

for v1, v2 in twos(t) do
	print(v1, v2)
end

In order to signal the for expression to stop iterating, we need to return nil as the first result.