una toda tabla pegar para otra mueve mover formato dentro cuadros copiar como anidada lua lua-table

lua - toda - pegar como tabla anidada



¿Cómo se copia una tabla Lua por valor? (15)

Advertencia: la solución marcada es INCORRECTA !

Cuando la tabla contiene tablas, las referencias a esas tablas se seguirán utilizando en su lugar. He estado buscando durante dos horas un error que estaba cometiendo, mientras era debido al uso del código anterior.

Así que necesitas verificar si el valor es una tabla o no. Si es así, deberías llamar a table.copy recursivamente!

Esta es la función correcta de table.copy:

function table.copy(t) local t2 = {}; for k,v in pairs(t) do if type(v) == "table" then t2[k] = table.copy(v); else t2[k] = v; end end return t2; end

Nota: Esto también puede estar incompleto cuando la tabla contiene funciones u otros tipos especiales, pero es posible que la mayoría de nosotros no lo necesitemos. El código anterior es fácilmente adaptable para aquellos que lo necesitan.

Recientemente escribí un poco de código Lua algo así como:

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

Obviamente, eso no era lo que quería hacer, ya que las variables contienen referencias a una tabla anónima, no a los valores de la tabla en Lua. Esto está claramente establecido en Programación en Lua , pero lo había olvidado.

Entonces, la pregunta es: ¿qué debo escribir en lugar de copy = a para obtener una copia de los valores en a ?


Copia de tabla tiene muchas definiciones potenciales. Depende de si desea una copia simple o profunda, si desea copiar, compartir o ignorar los metatables, etc. No existe una implementación única que pueda satisfacer a todos.

Un enfoque es simplemente crear una nueva tabla y duplicar todos los pares clave / valor:

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)

Tenga en cuenta que debe usar pairs lugar de ipairs , ya que los ipairs solo se ipairs en un subconjunto de las claves de la tabla (es decir, las claves enteras positivas consecutivas que comienzan en una en orden ipairs ).


Creo que la razón por la que Lua no tiene ''table.copy ()'' en sus bibliotecas estándar es porque la tarea no es precisa de definir. Como se muestra aquí, uno puede hacer una copia "a un nivel de profundidad" (lo que usted hizo), una copia profunda con o sin el cuidado de posibles referencias duplicadas. Y luego están los metatables.

Personalmente, me gustaría que ofrecieran una función incorporada. Solo si la gente no estuviera satisfecha con su semántica, tendrían que hacerlo ellos mismos. No muy a menudo, sin embargo, uno realmente tiene la necesidad de copiar por valor.


El proyecto stdlib (lamentablemente ligeramente documentado) tiene varias extensiones valiosas para varias de las bibliotecas incluidas con la distribución estándar de Lua. Entre ellos hay varias variaciones sobre el tema de la copia y fusión de tablas.

Esta biblioteca también se incluye en la distribución de Lua para Windows , y probablemente debería formar parte de la caja de herramientas de cualquier usuario serio de Lua.

Una cosa de la que hay que asegurarse al implementar cosas como esta a mano es el manejo adecuado de los metatables. Para las aplicaciones simples de tabla como estructura, probablemente no tenga metatables, y un simple bucle que usa pairs() es una respuesta aceptable. Pero si la tabla se utiliza como un árbol, o contiene referencias circulares, o tiene metatables, entonces las cosas se vuelven más complejas.


En la mayoría de los casos en los que necesitaba copiar una tabla, quería tener una copia que no compartiera nada con el original, de modo que cualquier modificación de la tabla original no afecte a la copia (y viceversa).

Todos los fragmentos de código que se han mostrado hasta el momento fallan al crear una copia para una tabla que puede tener claves compartidas o claves con tablas, ya que se dejarán apuntando a la tabla original. Es fácil ver si intenta copiar una tabla creada como: a = {}; a[a] = a a = {}; a[a] = a . La función de copia profunda a la que hace referencia Jon se encarga de eso, por lo que si necesita crear una copia real / completa, debe usarse la copia deepcopy .


En mi situación, cuando la información en la tabla es solo datos y otras tablas (excluyendo funciones, ...), es la siguiente línea de código la solución ganadora:

local copyOfTable = json.decode( json.encode( sourceTable ) )

Estoy escribiendo el código Lua para algunos sistemas de automatización del hogar en Fibaro Home Center 2. La implementación de Lua es muy limitada, ya que no hay una biblioteca central de funciones a las que puedas referirte. Cada función debe ser declarada en el código para mantener el código en servicio, por lo que las soluciones de una línea como esta son favorables.


Eso es tan bueno como para las tablas básicas. Use algo como deepcopy si necesita copiar tablas con metatables.


Este podría ser el método más simple:

local data = {DIN1 = "Input(z)", DIN2 = "Input(y)", AINA1 = "Input(x)"} function table.copy(mytable) --mytable = the table you need to copy newtable = {} for k,v in pairs(mytable) do newtable[k] = v end return newtable end new_table = table.copy(data) --copys the table "data"


Esto es lo que realmente hice:

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

Como lo menciona Doub , si las claves de su mesa no son estrictamente monotónicas, deberían ser pairs no ipairs .

También encontré una función de deepcopy que es más robusta:

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

Maneja tablas y metatables llamándose a sí mismo de forma recursiva ( que es su propia recompensa ). Uno de los bits inteligentes es que puede pasarle cualquier valor (sea una tabla o no) y se copiará correctamente. Sin embargo, el costo es que potencialmente podría desbordar la pila. Por lo tanto, e incluso una función más robusta (no recursiva) podría ser necesaria.

Pero eso es excesivo para el caso muy simple de querer copiar una matriz en otra variable.


La versión completa de copia profunda, manejando las 3 situaciones:

  1. Tabla circular de referencia
  2. Teclas que también son tablas.
  3. Metatable

La versión general:

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

O la versión de la mesa:

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

Basado en las funciones de lua-users.org/wiki/CopyTable ''y Alan Yates ''.


No olvide que las funciones también son referencias, por lo que si desea "copiar" por completo todos los valores, también necesitará obtener funciones separadas; sin embargo, la única forma que conozco de copiar una función es usar loadstring(string.dump(func)) , que de acuerdo con el manual de referencia de Lua, no funciona para funciones con valores superiores.

do local function table_copy (tbl) local new_tbl = {} for key,value in pairs(tbl) do local value_type = type(value) local new_value if value_type == "function" then new_value = loadstring(string.dump(value)) -- Problems may occur if the function has upvalues. elseif value_type == "table" then new_value = table_copy(value) else new_value = value end new_tbl[key] = new_value end return new_tbl end table.copy = table_copy end


Para jugar un poco al golf de código legible, aquí hay una versión corta que maneja los casos difíciles estándar:

  • tablas como llaves,
  • preservar los metatables, y
  • Tablas recursivas.

Podemos hacerlo en 7 líneas:

function copy(obj, seen) if type(obj) ~= ''table'' then return obj end if seen and seen[obj] then return seen[obj] end local s = seen or {} local res = setmetatable({}, getmetatable(obj)) s[obj] = res for k, v in pairs(obj) do res[copy(k, s)] = copy(v, s) end return res end

Hay una breve reseña de las operaciones de copia profunda de Lua en esta lista .

Otra referencia útil es esta página wiki de Lua-users , que incluye un ejemplo sobre cómo evitar el __pairs __pairs.


Solo para ilustrar el punto, mi table.copy personal.copia también presta atención a los metatables:

function table.copy(t) local u = { } for k, v in pairs(t) do u[k] = v end return setmetatable(u, getmetatable(t)) end

No existe una función de copia suficientemente aceptada para ser llamada "estándar".


Una versión opcionalmente profunda, gráfica general, recursiva:

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

¿Quizás la copia metatable debería ser opcional también?