Lua Iterators
# Lua Iterators
An iterator is an object that can be used to traverse some or all elements of a standard template library container. Each iterator object represents a specific address within the container.
In Lua, an iterator is a structure that supports pointer-like behavior, allowing you to traverse each element of a collection.
* * *
## Generic for Iterators
The generic for internally stores the iterator function. In fact, it stores three values: the iterator function, a state constant, and a control variable.
The generic for iterator provides key/value pairs of a collection. The syntax is as follows:
for k, v in pairs(t) do print(k, v)end
In the code above, `k` and `v` are the variable list; `pairs(t)` is the expression list.
Look at the following example:
## Example
array ={"Google",""}
for key,value in ipairs(array)
do
print(key, value)
end
The output of the above code is:
1 Google2
In the example above, we used the default iterator function `ipairs` provided by Lua.
Now let's look at the execution process of the generic for:
* First, initialization: calculate the value of the expression after `in`. The expression should return the three values needed by the generic for: the iterator function, the state constant, and the control variable. Similar to multiple assignments, if the expression returns fewer than three values, they are automatically padded with `nil`, and any extra values are ignored.
* Second, call the iterator function with the state constant and control variable as arguments (Note: For the `for` structure, the state constant is not used; it is only obtained during initialization and passed to the iterator function).
* Third, assign the values returned by the iterator function to the variable list.
* Fourth, if the first returned value is `nil`, the loop ends; otherwise, execute the loop body.
* Fifth, go back to the second step and call the iterator function again.
In Lua, we often use functions to describe iterators. Each call to the function returns the next element of the collection. Lua's iterators include the following two types:
* Stateless iterators
* Stateful iterators
* * *
## Stateless Iterators
A stateless iterator is an iterator that does not retain any state. Therefore, in loops, we can use stateless iterators to avoid the extra cost of creating closures.
In each iteration, the iterator function is called with two variables (the state constant and the control variable) as arguments. A stateless iterator uses only these two values to get the next element.
A typical simple example of this stateless iterator is `ipairs`, which traverses each element of an array. The element index must be numeric.
In the following example, we use a simple function to implement an iterator that calculates the square of a number `n`:
## Example
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
for i,n in square,3,0
do
print(i,n)
end
The output of the above example is:
112439
The iteration state includes the table being traversed (the state constant that does not change during the loop) and the current index (the control variable). `ipairs` and the iterator function are very simple. We can implement them in Lua like this:
## Example
function iter (a, i)
i = i +1
local v = a
if v then
return i, v
end
end
function ipairs(a)
return iter, a,0
end
When Lua calls `ipairs(a)` to start the loop, it gets three values: the iterator function `iter`, the state constant `a`, and the initial control variable `0`. Then Lua calls `iter(a,0)` which returns `1, a` (unless `a` is `nil`). The second iteration calls `iter(a,1)` which returns `2, a`... and so on until the first `nil` element.
* * *
## Stateful Iterators
In many cases, iterators need to store multiple state information rather than just a simple state constant and control variable. The simplest method is to use closures. Another method is to encapsulate all state information into a table and use the table as the iterator's state constant. Since all information can be stored in the table in this case, the iterator function usually does not need a second argument.
In the following example, we create our own iterator:
## Example
array ={"Google",""}
function elementIterator (collection)
local index =0
local count =#collection
-- Closure function
return function()
index = index +1
if index 0 then arr = string.sub(str,1,locaStart-1) n = n + 1 end str = string.sub(str,locaEnd+1,string.len(str)) locaStart,locaEnd = string.find(str,newDeli) end if str ~= nil then arr = str end return arr end t = split("php,js", ",")for k, v in pairs(t) do print(k, v)end
The output is:
1 php 2 js
Welcome to discuss.
(#)Daoyankong
276***597@qq.com 8 years ago (2018-06-19)
4. #0 kimomi
dol***xie@163.com [](#)32 The generic for calls the closure function each time during iteration. The iterator function is only called once at the beginning.
For example:
function eleiter(t) local index = 0 print('in eleiter function') --> Says this each time the iterator function is called: in eleiter function return function() print('I am here.') --> Says this each time the closure function is called: I am here index = index + 1 return t endend t = {'one','two','three','four','five'}for ele in eleiter(t) do print(ele)end
Output:
in eleiter function I am here. one I am here. two I am here. three I am here. four I am here. five I am here.(javascript:;)kimomi
dol***xie@163.com 7 years ago (2019-11-07)
5. #0 asdf
asd***sdf.com [](#)7
The generic for maintains 3 elements internally:
* 1. The iterator function itself, e.g., `pairs(tab)`
* 2. The state constant of the iterator function, e.g., `tab`
* 3. The control variable of the iterator function, e.g., `idx`
**Requirement**: Each time the iterator function is called, the control variable changes once after the function executes. When the control variable meets the condition, it stops calling the iterator function again.
Example:
function iter (a, i) i = i + 1 local v = a if v then return i, v endendfunction ipairss (a) i=0; while(true) do k,v=iter(a,i) if k=nil then break; endend t={"asdf1","asdf2","asdf3","asdf4"}for k,v in ipairss(t) do //--Internally maintains iter, t, i three elements, where i is implicit--This is my understanding print(k,v)end
(javascript:;)
asdf
asd***sdf.com
7 years ago (2019-11-13)
6. #0 div2009
div***9@foxmail.com [](#)3 for k, v in pairs(t) do print(k, v)end
The role of k and v in the generic for: k serves as a variable storing the index, and v serves as a variable storing the value corresponding to the index. This is similar to the concept of array index and value in C language (C language: `a="a"`, 1 is the index, "a" is the value).
Whether using `pairs` or `ipairs`, both traverse `t` sequentially, with the index stored in `k` and the corresponding value in `v`, starting from 1.
The difference is that `pairs` will traverse and output everything, while `ipairs` stops when it encounters a nil value. In the following example, I use "a"~"d" as indices. `pairs` will output all. `ipairs` will stop output at the beginning because `t` is nil.
local t={} t=1 t=2 t=3 t=4print("pairs:") -- Output using pairs for k,v in pairs(t) do print(k .." , ".. v)endprint("ipairs:") -- Output using ipairs for g,b in ipairs(t) do print(g .." , ".. b)end
Result:
pairs: a , 1 d , 4 c , 3 b , 2 ipairs:(javascript:;)div2009
div***9@foxmail.com 6 years ago (2020-03-07)
7. #0 Ingnary
ing***yk@outlook.com [](#)4
**Another difference between pairs and ipairs**
* **ipairs** skips non-numeric indices during iteration.
* **pairs** does not skip them during iteration.
tab = {1,2} tab=6for i,v in ipairs(tab) do print(i.." "..v) print(tab)endprint("----------------------------")for i,v in pairs(tab) do print(i.." "..v) print(tab)end
Result:
1 162 26----------------------------1 162 26 key 66
(javascript:;)
Ingnary
ing***yk@outlook.com
6 years ago (2021-01-10)
8. #0 Self-improving Sun
694***050@qq.com [](#)6 The `iter` implementation in the notes has a bug and is different from the actual one. The exit condition is always `nil`, but it misses `false`.
You can see the differences from my example code:
array = {"Google", ""}for key,value in ipairs(array) do print(ke
YouTip