YouTip LogoYouTip

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
← Lua Object OrientedLua Strings β†’