Bienvenidos sean a este post, hoy hablaremos sobre los iteradores pero que es un iterador? Es cualquier construccion que te permite iterar, iterar significa volver a hacer o en nuestro caso volver a trabajar, sobre los elementos de una coleccion, en Lua nosotros representamos tipicamente iteradores con funciones:
Cada vez que llamamos a una funcion, esta nos retorna el proximo elemento de la coleccion
Roberto Lerusalimschy
Cada iterador necesita mantener algun estado entre las sucesivas llamadas, esto es para indicar donde es y como debe proceder desde ahi, y aqui entra en accion los cierres que nos provee un excelente mecanismo para esta tarea.
Nota: Recuerden que un cierre es una funcion que accede una o mas variables locales desde su entorno cerrado
Dichas variables mantienen su valor a traves de las sucesivas llamadas al cierre permitiendo al cierre recordar donde esta a lo largo de una traversal, pero si nosotros necesitamos crear otro cierre debemos crear tambien variables no locales. Una construccion tipica de un cierre incluye a dos funciones: la funcion en si misma y una fabrica o factory, la funcion que crea el cierre, analicemos el siguiente ejemplo:
function valores (f)
local i = 0
return function() i = i + 1; return f[i] end
end
Este ejemplo es un iterator bien simple que a diferencia de ipairs no nos devuelve el indice sino solamente el valor, en este caso la fabrica es valores porque cada vez que llamamos a esta fabrica la misma crea un nuevo cierre (el iterador en si mismo), esto provoca que el cierre mantenga su estado en las variables externas f e i, y cada vez que llamamos al iterator devolvera el proximo valor de la lista t, una vez pasado el ultimo elemento el iterator devuelve un valor nil lo cual simboliza el final de la iteracion, ese iterator podriamos usarlo con un bucle while como veremos a continuacion:
t = {10, 20, 30}
iter = valores(t)
while true do
local elemento = iter()
if elemento == nil then break end
print(elemento)
end
Primero crearemos una tabla con tres datos, luego crearemos un variable llamada iter e iniciaremos el iterator valores y le informaremos el valor de t, despues usaremos un bucle while infinito, en este caso crearemos una variable local llamada elemento y le asignamos el iterator iter para ser llamado, despues tendremos un condicional donde verificara si elemento es igual a nil, en caso de ser verdadero ejecutara break para salir del bucle sino mostrara en pantalla el valor de elemento, una forma mas sencilla de hacer el ejemplo anterior es utilizar el for generico porque al fin y al cabo lo tenemos para eso, no?, veamos el codigo:
t = {10, 20, 30}
for elemento in valores(t) do
print(elemento)
end
Como pueden ver se simplifico bastante nuestro codigo, como vimos en este post este tipo de for trabaja la iteracion de forma interna, por esto no es necesaria la variable iter, tambien la otra propiedad de este for es que mira todos los elementos hasta que encuentra un nil y sale del mismo, esto ocasiona que el condicional ya no es necesario, veamos la salida de este programa:
tinchicus@dbn001dsk:~/lenguaje/lua$ lua5.3 prueba.lua
10
20
30
tinchicus@dbn001dsk:~/lenguaje/lua$
Antes de continuar veamos como quedo nuestro codigo final:
prueba.lua
function valores (f)
local i = 0
return function() i = i + 1; return f[i] end
end
t = {10, 20, 30}
for elemento in valores(t) do
print(elemento)
end
Hasta aca hemos visto un ejemplo simple de iterator pero ahora veremos otro iterator un poco mas complejo que nos permitira atravesar todas las palabras de una archivo de entrada, para ello usaremos el siguiente codigo:
iterator.lua
function palabrasTodas()
local linea = io.read()
local pos = 1
return function()
while linea do
local i,f = string.find(linea, "%w+", pos)
if i then
pos = f + 1
return string.sub(linea, i, f)
else
linea = io.read()
pos = 1
end
end
return nil
end
end
for palabra in palabrasTodas() do
print(palabra)
end
Primero hablemos de la funcion, en este caso primero crearemos dos variables locales llamadas linea y pos, las cuales almacenaran el texto ingresado y la posicion en la linea respectivamente, el texto en linea sera ingresado por medio de io.read y pos iniciara con un valor de 1, como dijimos en otras ocasiones el valor inicial de Lua, esto nos posibilitara siempre generar la siguiente palabra, el siguiente bloque es el iterator en si, veamos al mismo:
return function()
while linea do
local i,f = string.find(linea, "%w+", pos)
if i then
pos = f + 1
return string.sub(linea, i, f)
else
linea = io.read()
pos = 1
end
end
return nil
end
En este caso usaremos un bucle while donde verificara que existe algo en linea, primero creara dos variables locales llamadas i y f (por inicio y final) donde usaremos la funcion find de string, en este primero pasaremos a linea (el cual va a ser el texto donde buscaremos), luego pasaremos el parametro (en este caso usamos un parametro que busca coincidencias de varios caracteres alfanumericos), y por ultimo le informamos la posicion de inicio, si encuentra alguna palabra actualizara los valores de i y f a las posicones donde se encontro la palabra, primer y ultimo caracter respectivamente, despues tendremos un condicional donde si i tiene un valor quera decir que existe una «palabra» donde pasara a actualizar a pos que le asignara el valor de f y le sumara 1, despues utilizara sub para recortar la palabra de linea por medio de los valores de i y f, por ultimo devolviendo de la funcion ese valor, de lo contrario si no recibio nada procedera a solicitar otra linea y reiniciara a pos al valor 1, si salimos del while porque no encontro mas lineas devuelve un nil y sale definitivamente de la funcion, por ultimo usaremos un bucle for generico para crear palabra de las almacenadas en linea, y la mostraremos en pantalla, probemos el programa para ver su salida en el siguiente video
Como pueden ver no importa la cantidad de palabras que ingresemos siempre nos separara las mismas, como pueden ver solamente las palabras y omite los caracteres como espacio, comas o signos de pregunta y/o interrogacion.
Nota: Para salir del bucle en el programa presionen Ctrl+D.
En resumen, hoy hemos visto como crear nuestros propios iteradores, como trabajan con los cierres, como un iterador simple nos da una pequeña ayuda, despues vimos un iterador msa complejo que nos permitio obtener todas las palabras de una linea, espero les haya sido util sigueme en Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Tambien podes donar
Es para mantenimiento del sitio, gracias!
$1.50