Buscar..


Genérico para bucle

Los iteradores utilizan una forma del bucle for conocido como el bucle for genérico .

La forma genérica del bucle for utiliza tres parámetros:

  1. Una función de iterador que se llama cuando se necesita el siguiente valor. Recibe tanto el estado invariante como la variable de control como parámetros. Devolviendo nil señales de terminación.
  2. El estado invariante es un valor que no cambia durante la iteración. Normalmente es el tema del iterador, como una tabla, cadena o datos de usuario.
  3. La variable de control representa un valor inicial para la iteración.

Podemos escribir un bucle for para iterar todos los pares clave-valor en una tabla usando la siguiente función.

local t = {a=1, b=2, c=3, d=4, e=5}

-- next is the iterator function
-- t is the invariant state
-- nil is the control variable (calling next with a nil gets the first key)
for key, value in next, t, nil do
  -- key is the new value for the control variable
  print(key, value) 
  -- Lua calls: next(t, key)  
end

Iteradores estándar

La biblioteca estándar de Lua proporciona dos funciones de iterador que pueden usarse con un bucle for para atravesar pares clave-valor dentro de las tablas.

Para iterar sobre una tabla de secuencias podemos usar la función de biblioteca ipairs .

for index, value in ipairs {'a', 'b', 'c', 'd', 'e'} do
  print(index, value)  --> 1 a, 2 b, 3 c, 4 d, 5 e
end

Para iterar sobre todas las claves y valores en cualquier tabla podemos usar los pares de funciones de la biblioteca.

for key, value in pairs {a=1, b=2, c=3, d=4, e=5} do
  print(key, value)  --> e 5, c 3, a 1, b 2, d 4  (order not specified)
end

Iteradores sin estado

Ambos pares y ipairs representan iteratas sin estado. Un iterador sin estado usa solo el genérico para la variable de control del bucle y el estado invariante para calcular el valor de iteración.

Pares iterador

Podemos implementar el iterador de pairs sin estado usando la next función.

-- generator function which initializes the generic for loop
local function pairs(t)
  -- next is the iterator function
  -- t is the invariant state
  -- control variable is nil
  return next, t, nil
end

Ipairs Iterator

Podemos implementar el iterador ipairs sin ipairs en dos funciones separadas.

-- function which performs the actual iteration
local function ipairs_iter(t, i)
  local i = i + 1  -- next index in the sequence (i is the control variable)
  local v = t[i]   -- next value (t is the invariant state)
  if v ~= nil then
    return i, v    -- index, value
  end
  return nil       -- no more values (termination)
end

-- generator function which initializes the generic for loop
local function ipairs(t)
  -- ipairs_iter is the iterator function
  -- t is the invariant state (table to be iterated)
  -- 0 is the control variable (first index)
  return ipairs_iter, t, 0
end

Iterador de caracteres

Podemos crear nuevos iteradores sin estado mediante el cumplimiento del contrato del bucle genérico for .

-- function which performs the actual iteration
local function chars_iter(s, i)
  if i < #s then
    i = i + 1
    return i, s:sub(i, i)
  end
end

-- generator function which initializes the generic for loop
local function chars(s)
  return chars_iter, s, 0
end

-- used like pairs and ipairs
for i, c in chars 'abcde' do
    print(i, c) --> 1 a, 2 b, 3 c, 4 f, 5 e
end

Iterador de números primos

Este es un ejemplo más simple de un iterador sin estado.

-- prime numbers iterator
local incr = {4, 1, 2, 0, 2}
function primes(s, p, d)
   s, p, d = s or math.huge, p and p + incr[p % 6] or 2, 1
   while p <= s do
      repeat
         d = d + incr[d % 6]
         if d*d > p then return p end
      until p % d == 0
      p, d = p + incr[p % 6], 1
   end
end

-- print all prime numbers <= 100
for p in primes, 100 do  -- passing in the iterator (do not call the iterator here)
   print(p)  -->  2  3  5  7  11 ... 97
end

-- print all primes in endless loop
for p in primes do  -- please note: "in primes", not "in primes()"
   print(p)
end

Iteradores de estado

Los iteradores de estado llevan información adicional sobre el estado actual del iterador.

Usando tablas

El estado de adición se puede empaquetar en el genérico para el estado invariante del bucle .

  local function chars_iter(t, i)
    local i = i + 1
    if i <= t.len then
      return i, t.s:sub(i, i)
    end
  end

  local function chars(s)
    -- the iterators state
    local t = {
      s = s,    -- the subject
      len = #s  -- cached length
    }
    return chars_iter, t, 0
  end

  for i, c in chars 'abcde' do
    print(i, c) --> 1 a, 2 b, 3 c, 4 d, 5 e
  end

Utilizando cierres

Estado adicional puede ser envuelto dentro de una función de cierre. Dado que el estado está completamente contenido en el alcance del cierre, el estado invariable y la variable de control no son necesarios.

  local function chars(s)
    local i, len = 0, #s
    return function() -- iterator function
      i = i + 1
      if i <= len then
        return i, s:sub(i, i)
      end
    end
  end

  for i, c in chars 'abcde' do
    print(i, c) --> 1 a, 2 b, 3 c, 4 d, 5 e
  end

Utilizando coroutines

Se puede contener un estado adicional dentro de una rutina, de nuevo, el estado invariable y la variable de control no son necesarios.

  local function chars(s)
    return coroutine.wrap(function()
      for i = 1, #s do
        coroutine.yield(s:sub(i, i))
      end
    end)
  end

  for c in chars 'abcde' do
    print(c) --> a, b, c, d, e
  end


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow