Lua iterator


An iterator is an object that can be used to traverse some or all elements in a standard template library container. Each iterator object represents a certain address in the container

In Lua, an iterator is a structure that supports pointer types, which can traverse each element of a collection.


Generic for iterator

Generic for saves the iteration function internally. In fact, it saves three values: iteration function, state constant, and control variable.

The generic for iterator provides the key/value pair of the collection. The syntax format is as follows:

for k, v in pairs(t) do
    print(k, v)
end

In the above code, k, v are variable lists; pair(t) is an expression list .

View the following example:

array = {"Lua", "Tutorial"}

for key,value in ipairs(array) 
do
   print(key, value)
end

The execution output of the above code is:

1  Lua
2  Tutorial

In the above example we used the iteration function ipairs provided by Lua by default.

Let’s take a look at the execution process of normative for:

  • First, initialize and calculate the value of the expression after in. The expression should return what normative for requires. Three values: iteration function, state constant, control variable; just like multi-valued assignment, if the number of results returned by the expression is less than three, it will be automatically filled with nil, and the excess will be ignored.

  • Second, call the iteration function with the state constant and control variable as parameters (note: for the for structure, the state constant is of no use, only get its value during initialization and pass it to the iterative function).

  • Third, assign the value returned by the iteration function to the variable list.

  • Fourth, if the first value returned is nil, the loop ends, otherwise the loop body is executed.

  • Fifth, go back to the second step and call the iteration function again

. In Lua, we often use functions to describe iterators. Each time the function is called, the next element of the collection is returned. Lua's iterators include the following two types:

  • Stateless iterator

  • Multi-state iterator


Stateless iterator

Stateless iterator refers to an iterator that does not retain any state, so in a loop we can use stateless iterators to avoid creating closures Cost extra.

Each iteration, the iteration function is called with the values ​​​​of two variables (state constants and control variables) as parameters. A stateless iterator only uses these two values ​​​​to obtain the next element.

The typical simple example of this kind of stateless iterator is ipairs, which traverses each element of the array.

In the following example, we use a simple function to implement the iterator and realize the square of the number n:

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 result of the above example is:

1	1
2	4
3	9

The status of the iteration includes The traversed table (status constant that does not change during the loop) and the current index subscript (control variable), ipairs and iteration functions are very simple. We can implement it in Lua like this:

function iter (a, i)
    i = i + 1
    local v = a[i]
    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: iterative function iter, state constant a, and control variable initial value 0; then Lua calls iter(a,0) to return 1, a[1 ] (unless a[1]=nil); the second iteration calls iter(a,1) to return 2, a[2]... until the first nil element.


Multi-state iterator

In many cases, iterators need to save multiple state information instead of simple state constants and control variables. The simplest way is to use closures , and another method is to encapsulate all status information into a table and use the table as the status constant of the iterator. Because in this case all the information can be stored in the table, the iteration function usually does not require a second parameter. .


We created our own iterator in the following example:

array = {"Lua", "Tutorial"}

function elementIterator (collection)
   local index = 0
   local count = #collection
   -- 闭包函数
   return function ()
      index = index + 1
      if index <= count
      then
         --  返回迭代器的当前元素
         return collection[index]
      end
   end
end

for element in elementIterator(array)
do
   print(element)
end

The output result of the above example is:

Lua
Tutorial

In the above example we can As you can see, the closure function is used in elementIterator to calculate the size of the set and output each element.