Ir al contenido principal

Iteradores en Lua

Los iteradores son construcciones del lenguaje que nos permiten recorrer los elementos de una tabla de manera ordenada y sencilla. Piensa en un iterador como un ayudante que va extrayendo, uno por uno, todos los elementos que guardaste en una caja (tabla), para que puedas examinarlos o trabajar con ellos.

El uso más común de los iteradores es dentro de los bucles for, donde nos facilitan enormemente la tarea de procesar cada elemento de una tabla sin tener que preocuparnos de llevar la cuenta manualmente de las posiciones o claves.

¿Cómo funcionan los iteradores?

El principio es muy simple: en cada vuelta del bucle for, el iterador se encarga de devolver el siguiente elemento de la tabla. Cuando ya no quedan más elementos, el iterador devuelve nil y el bucle termina automáticamente.

Veamos un ejemplo básico para entenderlo mejor:

paises = {"España", "Francia", "Italia", "Portugal"}

for indice, valor in ipairs(paises) do
    print(indice, valor)
end

Si ejecutamos este código, obtenemos:

1       España
2       Francia
3       Italia
4       Portugal

Como puedes ver, el iterador ipairs() nos ha devuelto, en cada iteración, dos valores: el índice (posición) del elemento y su valor.

Iteradores genéricos en Lua

Lua incluye dos iteradores genéricos en su librería estándar que cubren la mayoría de las necesidades básicas:

  • ipairs(): para recorrer arrays (tablas con índices numéricos)
  • pairs(): para recorrer diccionarios (tablas con claves de cualquier tipo)

Veamos cada uno en detalle.

El iterador ipairs()

El iterador ipairs() está diseñado específicamente para recorrer arrays, es decir, tablas cuyos elementos están indexados numéricamente. Su nombre viene de "integer pairs" (pares de enteros).

Características de ipairs():

  • Recorre los elementos en orden secuencial
  • Devuelve el índice numérico y el valor de cada elemento
  • Garantiza el orden de iteración
  • Se detiene al encontrar el primer nil o hueco en la secuencia

Veamos un ejemplo práctico:

frutas = {"manzana", "naranja", "plátano", "pera", "uva"}

print("Listado de frutas:")
for i, fruta in ipairs(frutas) do
    print("Posición " .. i .. ": " .. fruta)
end

Resultado:

Listado de frutas:
Posición 1: manzana
Posición 2: naranja
Posición 3: plátano
Posición 4: pera
Posición 5: uva

Si no necesitas el índice, puedes usar un guion bajo _ para indicar que no lo vas a utilizar:

for _, fruta in ipairs(frutas) do
    print("Me gusta la " .. fruta)
end

El iterador pairs()

El iterador pairs() es más versátil y puede recorrer cualquier tipo de tabla, tanto arrays como diccionarios (tablas con claves no numéricas).

Características de pairs():

  • Puede recorrer tablas con cualquier tipo de clave
  • No garantiza un orden específico de iteración para diccionarios
  • Devuelve la clave (de cualquier tipo) y el valor
  • Para arrays, se comporta similar a ipairs() pero con orden garantizado

Ejemplo con un diccionario:

parametros = {
    host = "localhost",
    puerto = 5432,
    usuario = "admin",
    basedatos = "mibd"
}

print("Configuración:")
for clave, valor in pairs(parametros) do
    print(clave .. " = " .. valor)
end

Posible resultado (el orden puede variar):

Configuración:
usuario = admin
puerto = 5432
basedatos = mibd
host = localhost

Como puedes observar, los elementos no se han mostrado en el orden en que los definimos. Esto es normal con pairs() cuando trabajamos con diccionarios.

Ejemplo con un array usando pairs()

colores = {"rojo", "verde", "azul", "amarillo"}

for indice, color in pairs(colores) do
    print("Color " .. indice .. ": " .. color)
end

Resultado:

Color 1: rojo
Color 2: verde
Color 3: azul
Color 4: amarillo

Para arrays, pairs() sí mantiene el orden secuencial.

Comparación entre ipairs() y pairs()

Veamos un ejemplo comparativo para entender mejor las diferencias:

-- Array de países
paises = {"Suiza", "España", "Colombia", "Italia", "Francia"}

-- Diccionario de configuración
config = {
    idioma = "español",
    tema = "oscuro",
    notificaciones = true
}

-- Usando ipairs() con el array
print("=== Usando ipairs() con array ===")
for i, pais in ipairs(paises) do
    print(i, pais)
end

-- Usando pairs() con el array
print("\n=== Usando pairs() con array ===")
for i, pais in pairs(paises) do
    print(i, pais)
end

-- Usando ipairs() con el diccionario
print("\n=== Usando ipairs() con diccionario ===")
for clave, valor in ipairs(config) do
    print(clave, valor)
end
-- No imprime nada porque ipairs() no funciona con diccionarios

-- Usando pairs() con el diccionario
print("\n=== Usando pairs() con diccionario ===")
for clave, valor in pairs(config) do
    print(clave, valor)
end

Resultado:

=== Usando ipairs() con array ===
1       Suiza
2       España
3       Colombia
4       Italia
5       Francia

=== Usando pairs() con array ===
1       Suiza
2       España
3       Colombia
4       Italia
5       Francia

=== Usando ipairs() con diccionario ===

=== Usando pairs() con diccionario ===
tema    oscuro
idioma  español
notificaciones  true

Conclusiones de la comparación:

  1. Con arrays, tanto ipairs() como pairs() funcionan bien
  2. ipairs() no puede iterar diccionarios (tablas con claves no numéricas)
  3. pairs() funciona con cualquier tipo de tabla
  4. Para arrays, ambos mantienen el orden; para diccionarios, pairs() no garantiza orden

¿Cuándo usar cada iterador?

La elección del iterador depende del tipo de tabla que estés manejando:

Usa ipairs() cuando:

  • Trabajas con arrays (listas secuenciales)
  • Necesitas garantizar el orden de iteración
  • El índice numérico es importante para tu lógica
  • Quieres que el bucle se detenga al encontrar el primer nil

Usa pairs() cuando:

  • Trabajas con diccionarios (tablas con claves no numéricas)
  • Las claves no son números
  • No te importa el orden de iteración
  • Necesitas recorrer todos los pares clave-valor sin importar su tipo

Casos de uso prácticos

Calcular el total de una lista de precios

precios = {15.50, 23.00, 8.75, 42.30, 19.99}
total = 0

for _, precio in ipairs(precios) do
    total = total + precio
end

print("Total: " .. total .. " euros")

Validar configuración de usuario

configuracion = {
    nombre = "Ana García",
    edad = 28,
    email = "ana@ejemplo.com",
    activo = true
}

print("Validando configuración:")
for campo, valor in pairs(configuracion) do
    if valor == nil or valor == "" then
        print("ERROR: El campo " .. campo .. " está vacío")
    else
        print("OK: " .. campo .. " = " .. tostring(valor))
    end
end

Buscar un elemento en una lista

usuarios = {"pedro", "maria", "juan", "laura", "carlos"}
buscar = "juan"
encontrado = false

for i, usuario in ipairs(usuarios) do
    if usuario == buscar then
        print("Usuario encontrado en la posición " .. i)
        encontrado = true
        break
    end
end

if not encontrado then
    print("Usuario no encontrado")
end

Crear un menú interactivo

opciones = {
    "Ver perfil",
    "Editar datos",
    "Cambiar contraseña",
    "Cerrar sesión"
}

print("=== MENÚ PRINCIPAL ===")
for num, opcion in ipairs(opciones) do
    print(num .. ". " .. opcion)
end
print("\nSelecciona una opción (1-" .. #opciones .. "):")

Errores comunes al usar iteradores

Error 1: Usar ipairs() con diccionarios

-- ❌ INCORRECTO
datos = {nombre = "Juan", edad = 30}
for i, v in ipairs(datos) do  -- No imprime nada
    print(i, v)
end

-- ✓ CORRECTO
for clave, valor in pairs(datos) do
    print(clave, valor)
end

Error 2: Modificar la tabla durante la iteración

-- ⚠️ CUIDADO: esto puede dar resultados inesperados
numeros = {1, 2, 3, 4, 5}
for i, num in ipairs(numeros) do
    if num % 2 == 0 then
        table.remove(numeros, i)  -- Modifica la tabla que estamos iterando
    end
end

Es mejor crear una nueva tabla con los elementos que quieres mantener:

-- ✓ MEJOR PRÁCTICA
numeros = {1, 2, 3, 4, 5}
impares = {}

for _, num in ipairs(numeros) do
    if num % 2 ~= 0 then
        table.insert(impares, num)
    end
end

Error 3: Asumir orden con pairs() en diccionarios

-- El orden puede variar en cada ejecución
puntuaciones = {juan = 100, ana = 95, pedro = 87}

-- No asumas que siempre se imprimirán en el mismo orden
for nombre, puntos in pairs(puntuaciones) do
    print(nombre .. ": " .. puntos)
end

Resumen

Los iteradores son herramientas fundamentales en Lua que simplifican enormemente el trabajo con tablas:

  • ipairs() es tu mejor opción para arrays y listas secuenciales
  • pairs() es versátil y funciona con cualquier tipo de tabla
  • Los iteradores manejan automáticamente el recorrido y la detención del bucle
  • Elegir el iterador correcto hace tu código más claro y eficiente

En próximos artículos exploraremos conceptos más avanzados como la creación de iteradores personalizados, pero con ipairs() y pairs() ya tienes las herramientas necesarias para la mayoría de situaciones cotidianas en tus programas Lua.