Lua - Iteradores
Iterator es una construcción que le permite atravesar los elementos de la denominada colección o contenedor. En Lua, estas colecciones a menudo se refieren a tablas, que se utilizan para crear varias estructuras de datos como matrices.
Genérico para iterador
Un iterador genérico para proporciona los pares clave-valor de cada elemento de la colección. A continuación se ofrece un ejemplo sencillo.
array = {"Lua", "Tutorial"}
for key,value in ipairs(array)
do
print(key, value)
end
Cuando ejecutamos el código anterior, obtendremos el siguiente resultado:
1 Lua
2 Tutorial
El ejemplo anterior usa la función de iterador ipairs predeterminada proporcionada por Lua.
En Lua usamos funciones para representar iteradores. Según el mantenimiento del estado en estas funciones de iterador, tenemos dos tipos principales:
- Iteradores sin estado
- Iteradores con estado
Iteradores sin estado
Por el nombre mismo podemos entender que este tipo de función iteradora no retiene ningún estado.
Veamos ahora un ejemplo de cómo crear nuestro propio iterador usando una función simple que imprime los cuadrados de n números.
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
Cuando ejecutamos el programa anterior, obtendremos el siguiente resultado.
1 1
2 4
3 9
El código anterior se puede modificar ligeramente para imitar la forma en que funciona la función ipairs de los iteradores. Se muestra a continuación.
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
function squares(iteratorMaxCount)
return square,iteratorMaxCount,0
end
for i,n in squares(3)
do
print(i,n)
end
Cuando ejecutamos el programa anterior, obtendremos el siguiente resultado.
1 1
2 4
3 9
Iteradores con estado
El ejemplo anterior de iteración que usa la función no retiene el estado. Cada vez que se llama a la función, devuelve el siguiente elemento de la colección basándose en una segunda variable enviada a la función. Para mantener el estado del elemento actual, se utilizan cierres. El cierre retiene los valores de las variables en las llamadas a funciones. Para crear un nuevo cierre, creamos dos funciones, incluido el cierre en sí y una fábrica, la función que crea el cierre.
Veamos ahora un ejemplo de cómo crear nuestro propio iterador en el que usaremos cierres.
array = {"Lua", "Tutorial"}
function elementIterator (collection)
local index = 0
local count = #collection
-- The closure function is returned
return function ()
index = index + 1
if index <= count
then
-- return the current element of the iterator
return collection[index]
end
end
end
for element in elementIterator(array)
do
print(element)
end
Cuando ejecutamos el programa anterior, obtendremos el siguiente resultado.
Lua
Tutorial
En el ejemplo anterior, podemos ver que elementIterator tiene otro método dentro que usa el índice y el recuento de variables externas locales para devolver cada uno de los elementos de la colección aumentando el índice cada vez que se llama a la función.
Podemos crear nuestros propios iteradores de función usando el cierre como se muestra arriba y puede devolver múltiples elementos para cada una de las veces que iteramos a través de la colección.