2009-08-16 21 views
49

Necesito unir dos tablas, con el contenido del segundo sobrescribir el contenido en el primero si un elemento dado está en ambos. Miré pero las bibliotecas estándar no parecen ofrecer esto. ¿Dónde puedo obtener tal función?Lua - fusionar tablas?

+1

No hay una sola manera de hacer esto . ¿Estás comparando las claves o los valores en la tabla? ¿Es posible que las claves/valores sean otras tablas? ... –

+0

no necesito ningún tipo de comparación, pero necesitaré subtablas ... – RCIX

Respuesta

75
for k,v in pairs(second_table) do first_table[k] = v end 
+0

espere, ¿eso capta claves de cadena y cosas así? – RCIX

+0

sí, se manejan las claves de cadena –

+0

Esto debería funcionar con algunos ajustes para manejar subtablas. ¡Gracias! – RCIX

16

Esto es lo que ocurrió con base en la respuesta de Doug Currie:

function tableMerge(t1, t2) 
    for k,v in pairs(t2) do 
     if type(v) == "table" then 
      if type(t1[k] or false) == "table" then 
       tableMerge(t1[k] or {}, t2[k] or {}) 
      else 
       t1[k] = v 
      end 
     else 
      t1[k] = v 
     end 
    end 
    return t1 
end 
+6

Tenga en cuenta que generalmente es una mala idea meterse con los "espacios de nombres" de Lua estándar (como la tabla. *). Mejor hacer el tuyo. –

+4

"si no t1 [k] entonces t1 [k] = {} end" contiene un error sutil (¡encuéntrelo!) Mejor escríbalo como "t1 [k] = t1 [k] o {}". Además, ¿qué ocurre si t2 [k] es una tabla pero t1 [k] existe pero no es una tabla? Finalmente, "table1 [k] = v" debería ser "t1 [k] = v". – lhf

+0

Todos los puntos buenos, los arreglaré inmediatamente. – RCIX

10

¿No sería este trabajo correctamente?


function merge(t1, t2) 
    for k, v in pairs(t2) do 
     if (type(v) == "table") and (type(t1[k] or false) == "table") then 
      merge(t1[k], t2[k]) 
     else 
      t1[k] = v 
     end 
    end 
    return t1 
end 
+2

Sí, pero si miras la publicación original de RCIX, hubo una lógica diferente allí que luego se simplificó a dos declaraciones 'else' idénticas. Debería haberse simplificado aún más en lo que tienes aquí. – BMitch

+0

Me gusta la concisión de su respuesta, gracias. –

2

Aquí está la versión iterativa para la fusión profunda porque no me gustan los posibles desbordamientos de pila recursivos.

local merge_task = {} 
function merge_to_left_o(orig, new) 
    merge_task[orig] = new 

    local left = orig 
    while left ~= nil do 
     local right = merge_task[left] 
     for new_key, new_val in pairs(right) do 
     local old_val = left[new_key] 
     if old_val == nil then 
      left[new_key] = new_val 
     else 
      local old_type = type(old_val) 
      local new_type = type(new_val) 
      if (old_type == "table" and new_type == "table") then 
       merge_task[old_val] = new_val 
      else 
       left[new_key] = new_val 
      end 
     end 
     end 
     merge_task[left] = nil 
     left = next(merge_task) 
    end 
end 
+0

Olvidó comprobar si 'merge_task' desborda su memoria disponible ... – Irfy

+1

@Irfy, usted sabe que no puede hacer eso en Lua, ¿verdad? –

+1

Mi comentario fue un sarcasmo: si escapas de la recursión porque temes/espero un desbordamiento de la pila; y luego no verifique si su contenedor de tareas desborda su memoria, entonces no tiene mucho sentido escapar de la recursión en primer lugar. – Irfy

1

La respuesta de Doug Currie es la más simple para la mayoría de los casos. Si necesita una combinación más robusta de tablas, considere usar el método merge() de la biblioteca Penlight.

require 'pl' 
pretty.dump(tablex.merge({a=1,b=2}, {c=3,d=4}, true)) 

-- { 
-- a = 1, 
-- d = 4, 
-- c = 3, 
-- b = 2 
-- } 
+0

¿Cuál es el tercer parámetro, por cierto? –

+0

El tercer parámetro determina cómo se fusionan las tablas: 'true' para una unión,' false' para una intersección. https://github.com/stevedonovan/Penlight/blob/master/lua/pl/tablex.lua#L554 – Blackcoat

0

que preferían la versión de James por su sencillez y usarlo en mi utils.lua - lo hice añadir un cheque por tipo de tabla de gestión de errores.

function merge(a, b) 
    if type(a) == 'table' and type(b) == 'table' then 
     for k,v in pairs(b) do if type(v)=='table' and type(a[k] or false)=='table' then merge(a[k],v) else a[k]=v end end 
    end 
    return a 
end 

Gracias por esta función agradable que debería formar parte de la clase mesa de modo que se podría llamar a:merge(b) pero haciendo table.merge = function(a, b) ... no funcionaba para mí. Incluso podría ser comprimido a un chiste para los empollones reales :) clave

0
for k,v in pairs(t2) do t1[k] = v end 

para la solución de cadena

3

Para tabla numérica-índice de fusión:

for k,v in pairs(secondTable) do table.insert(firstTable, v) end