55 votes

Comment copier une table Lua par valeur?

Récemment, j'ai écrit un peu de code Lua quelque chose comme:

 local a = {}
for i = 1, n do
   local copy = a
   -- alter the values in the copy
end
 

Évidemment, ce n’était pas ce que je voulais faire puisque les variables contiennent des références à une table anonyme et non les valeurs de la table elle-même dans Lua. Ceci est clairement exposé dans la programmation en Lua , mais je l'avais oublié.

La question est donc de savoir quoi écrire au lieu de copy = a pour obtenir une copie des valeurs en a ?

43voto

Doub Points 838

La copie de la Table a de nombreuses définitions. Cela dépend si vous voulez simple ou copie en profondeur, si vous voulez copier, partager ou de les ignorer metatables, etc. Il n'existe pas de mise en œuvre qui pourrait satisfaire tout le monde.

Une approche consiste à simplement créer une nouvelle table et de dupliquer toutes les paires clé/valeur:

function table.shallow_copy(t)
  local t2 = {}
  for k,v in pairs(t) do
    t2[k] = v
  end
  return t2
end

copy = table.shallow_copy(a)

Notez que vous devez utiliser pairs au lieu de ipairs, depuis ipairs seulement effectuer une itération sur un sous-ensemble de la table de clés (ie. consécutives entier positif clés, en commençant à un dans l'ordre croissant).

12voto

islet8 Points 81

La version complète de deep copy, qui gère les 3 situations:

  1. Tableau de référence circulaire
  2. Touches qui sont aussi des tables
  3. Métatable

La version générale:

 local function deepcopy(o, seen)
  seen = seen or {}
  if o == nil then return nil end
  if seen[o] then return seen[o] end

  local no
  if type(o) == 'table' then
    no = {}
    seen[o] = no

    for k, v in next, o, nil do
      no[deepcopy(k, seen)] = deepcopy(v, seen)
    end
    setmetatable(no, deepcopy(getmetatable(o), seen))
  else -- number, string, boolean, etc
    no = o
  end
  return no
end
 

Ou la version de la table:

 function table.deepcopy(o, seen)
  seen = seen or {}
  if o == nil then return nil end
  if seen[o] then return seen[o] end


  local no = {}
  seen[o] = no
  setmetatable(no, deepcopy(getmetatable(o), seen))

  for k, v in next, o, nil do
    k = (type(k) == 'table') and k:deepcopy(seen) or k
    v = (type(v) == 'table') and v:deepcopy(seen) or v
    no[k] = v
  end
  return no
end
 

Basé sur les fonctions lua-users.org/wiki/CopyTable et Alan Yates .

10voto

Alan Yates Points 91

Une version récursive, généralement graphique-général, optionnellement profonde:

 function table.copy(t, deep, seen)
    seen = seen or {}
    if t == nil then return nil end
    if seen[t] then return seen[t] end

    local nt = {}
    for k, v in pairs(t) do
        if deep and type(v) == 'table' then
            nt[k] = table.copy(v, deep, seen)
        else
            nt[k] = v
        end
    end
    setmetatable(nt, table.copy(getmetatable(t), deep, seen))
    seen[t] = nt
    return nt
end
 

Peut-être que la copie métatable devrait être facultative également?

6voto

Jon Ericson Points 9703

Voici ce que j'ai fait:

for j,x in ipairs(a) do copy[j] = x end

Comme Doute mentionne, si votre table de clés ne sont pas strictement monotone croissante, il convient pairs pas ipairs.

J'ai aussi trouvé un deepcopy fonction qui est plus robuste:

function deepcopy(orig)
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in next, orig, nil do
            copy[deepcopy(orig_key)] = deepcopy(orig_value)
        end
        setmetatable(copy, deepcopy(getmetatable(orig)))
    else -- number, string, boolean, etc
        copy = orig
    end
    return copy
end

Il gère les tables et les metatables en appelant lui-même de manière récursive (qui est sa propre récompense). L'un des intelligente bits, c'est que vous pouvez passer n'importe quelle valeur (si une table ou pas) et il sera copié correctement. Cependant, le coût est qu'il pourrait potentiellement débordement de la pile. Donc, et même plus robuste (non récursif) la fonction peut être nécessaire.

Mais c'est overkill pour le cas très simple de vouloir copier un tableau dans une autre variable.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X