Lua - 合并表?

RCI*_*CIX 56 merge lua lua-table

我需要合并两个表,如果给定的项目同时存在,则第二个覆盖内容将包含在第一个表中.我看了,但标准库似乎没有提供这个.我在哪里可以获得这样的功能?

Dou*_*rie 85

for k,v in pairs(second_table) do first_table[k] = v end
Run Code Online (Sandbox Code Playgroud)

  • 如果索引与数组中的索引相同,这是否会覆盖当前表中的内容?如果您有两个带数字键[1],[2],[3]等的表,其中一个数据已经存在并且您只是迭代第二个表的键,还有[1],[2],[3]等并使用相同的键将数据添加到相同的位置到表一,你将覆盖原来的那些.你可以用first_table来解决这个问题[#first_table + k] = v.就我个人而言,我会使用tables.insert()来解决这个问题,尽管不确定它是否在2009年可用! (23认同)
  • 在 99% 的情况下,这将是正确的解决方案,但请记住,在具有引用其他表的表的应用程序中,这在面向对象模式中很常见,您可能需要进行额外的簿记。例如,如果给定表可能直接引用自身的原因有一些,您需要检查 `v==second_table`,如果是,则分配 `first_table`。表格也可以间接引用自己,但这可能是一本书要解决的问题。我只是想把它放在雷达上,所以'nuff说。 (2认同)
  • @Astridax 这就是提问者的要求。 (2认同)

RCI*_*CIX 17

以下是我根据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
Run Code Online (Sandbox Code Playgroud)

  • 请注意,混淆标准的Lua"命名空间"(如表.*)通常是个坏主意.最好自己做. (6认同)
  • "如果不是t1 [k]那么t1 [k] = {} end"包含一个微妙的bug(找到它!)最好把它写成"t1 [k] = t1 [k]或{}".另外,如果t2 [k]是一个表但是t1 [k]存在但不是表,会发生什么?最后,"table1 [k] = v"应为"t1 [k] = v". (4认同)

小智 11

这不能正常工作吗?


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
Run Code Online (Sandbox Code Playgroud)

  • 谁能解释为什么这里需要`t1[k] or false`? (4认同)
  • 是的,但是如果你看看RCIX的原始帖子,那里有一些不同的逻辑,后来简化为两个相同的`else`语句.它应该进一步简化为你在这里所拥有的. (2认同)

小智 6

对于数字索引表合并:

for k,v in pairs(secondTable) do table.insert(firstTable, v) end
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案是不是错误(因为“pairs”不能保证按数字顺序返回元素)?除了“table.insert”效率低下之外,请参阅/sf/answers/1069489851/(另请参阅其他答案) (3认同)

Ole*_*kov 5

这是深度合并的迭代版本,因为我不喜欢递归的潜在堆栈溢出。

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
Run Code Online (Sandbox Code Playgroud)

  • 我的评论是一种讽刺:如果你因为担心/预期堆栈溢出而逃避递归;然后不检查你的任务容器是否溢出你的内存,那么一开始逃避递归就没有多大意义。 (2认同)
  • @Irfy,用于 Lua 中的表或其他语言中的类似结构的“通用”内存通常比调用堆栈空间更丰富。当然,应该考虑哪种解决方案适合特定环境,而不是盲目地复制/粘贴其中一种。 (2认同)

Bla*_*oat 5

对于大多数情况,Doug Currie 的答案是最简单的。如果您需要更强大的表合并,请考虑使用Penlightmerge()库中的方法。

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

-- {
--   a = 1,
--   d = 4,
--   c = 3,
--   b = 2
-- }
Run Code Online (Sandbox Code Playgroud)