Aller au contenu principal
ShadowAcademy

Les langages / Lua / Coroutines et iterateurs

Itérateurs personnalisés

Les itérateurs permettent de parcourir des données personnalisées avec des boucles for. Lua permet de créer des itérateurs stateless (sans état) ou stateful (avec état) pour tout type de collection.

Itérateur simple

-- Itérateur qui compte de 1 à n
function compter(n)
  local i = 0
  return function()
    i = i + 1
    if i <= n then
      return i
    end
  end
end

-- Utilisation
for nombre in compter(5) do
  print(nombre)  -- 1, 2, 3, 4, 5
end

-- Itérateur avec pas personnalisé
function compteurPas(debut, fin, pas)
  local i = debut - pas
  return function()
    i = i + pas
    if i <= fin then
      return i
    end
  end
end

for n in compteurPas(0, 10, 2) do
  print(n)  -- 0, 2, 4, 6, 8, 10
end

Itérateur stateless

-- Itérateur pour parcourir à l'envers
function rpairs(t)
  -- Fonction itératrice
  local function iter(t, i)
    i = i - 1
    if i >= 1 then
      return i, t[i]
    end
  end
  -- Retourne: fonction, table, état initial
  return iter, t, #t + 1
end

-- Utilisation
local fruits = {"Pomme", "Banane", "Orange"}
for i, fruit in rpairs(fruits) do
  print(i, fruit)
end
-- 3 Orange
-- 2 Banane
-- 1 Pomme

Itérateur pour filtrer

-- Itérateur qui filtre les valeurs
function filtrer(t, predicat)
  local i = 0
  return function()
    i = i + 1
    while i <= #t do
      local valeur = t[i]
      if predicat(valeur) then
        return i, valeur
      end
      i = i + 1
    end
  end
end

-- Filtrer les nombres pairs
local nombres = {1, 2, 3, 4, 5, 6, 7, 8}
for i, n in filtrer(nombres, function(x) return x % 2 == 0 end) do
  print(i, n)  -- 2 2, 4 4, 6 6, 8 8
end

Itérateur chaînable

-- Créer un itérateur chaînable
local Iter = {}

function Iter.new(t)
  return setmetatable({data = t}, {__index = Iter})
end

function Iter:map(fn)
  local result = {}
  for i, v in ipairs(self.data) do
    table.insert(result, fn(v))
  end
  return Iter.new(result)
end

function Iter:filter(fn)
  local result = {}
  for i, v in ipairs(self.data) do
    if fn(v) then
      table.insert(result, v)
    end
  end
  return Iter.new(result)
end

function Iter:toArray()
  return self.data
end

-- Utilisation chaînée
local nombres = {1, 2, 3, 4, 5}
local resultat = Iter.new(nombres)
  :filter(function(x) return x % 2 == 0 end)
  :map(function(x) return x * 2 end)
  :toArray()

for _, v in ipairs(resultat) do
  print(v)  -- 4, 8
end

1 exercice pour cette lecon

Les exercices demandent un compte : il faut bien enregistrer votre progression quelque part. La lecture, elle, reste libre. Creer un compte

  • Itérateur personnalisé difficile 35 XP