Skip to content

Instantly share code, notes, and snippets.

@qizhihere
Created July 4, 2015 07:47
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save qizhihere/cb2a14432d9bf65693ad to your computer and use it in GitHub Desktop.
Save qizhihere/cb2a14432d9bf65693ad to your computer and use it in GitHub Desktop.
merge two tables in lua
function table.merge(t1, t2)
for k,v in ipairs(t2) do
table.insert(t1, v)
end
return t1
end
@AMD-NICK
Copy link

говно способ, чувак

@dragonfly-net
Copy link

в 5.1.4 не работает. А если и заработает, то будет так же модифицирован оригинальный t1

@dmitrii-eremin
Copy link

I don't know why this code snip is the first in google, but it's not the best one implementation. Simplest but with basic errors.
Here is how I see this:

local function table_clone_internal(t, copies)
  if type(t) ~= "table" then return t end
  
  copies = copies or {}
  if copies[t] then return copies[t] end

  local copy = {}
  copies[t] = copy

  for k, v in pairs(t) do
    copy[table_clone_internal(k, copies)] = table_clone_internal(v, copies)
  end

  setmetatable(copy, table_clone_internal(getmetatable(t), copies))

  return copy
end

local function table_clone(t)
  -- We need to implement this with a helper function to make sure that
  -- user won't call this function with a second parameter as it can cause
  -- unexpected troubles
  return table_clone_internal(t)
end

local function table_merge(...)
  local tables_to_merge = {...}
  assert(#tables_to_merge > 1, "There should be at least two tables to merge them")

  for k, t in ipairs(tables_to_merge) do
    assert(type(t) == "table", string.format("Expected a table as function parameter %d", k))
  end

  local result = table_clone(tables_to_merge[1])

  for i = 2, #tables_to_merge do
    local from = tables_to_merge[i]
    for k, v in pairs(from) do
      if type(v) == "table" then
        result[k] = result[k] or {}
        assert(type(result[k]) == "table", string.format("Expected a table: '%s'", k))
        result[k] = table_merge(result[k], v)
      else
      result[k] = v
      end
    end
  end

  return result
end

return {
  table_clone = table_clone,
  table_merge = table_merge,
}

These set of functions allow user to clone and to merge tables. Merge clones the original table first, keep this in mind when you're thinking about performance. But hey, it's quite simple to remove a table cloning, just replace local result = table_clone(tables_to_merge[1]) with local result = tables_to_merge[1] and that's all.
BTW, table_merge accepts various amount of parameters and will merge all of them.
You can use this as a module, just place this code somewhere in your working folder and import this later on and that's it.

@LRagji
Copy link

LRagji commented Oct 30, 2021

TLDR; I understand @dmitrii-eremin that you code helps to clone the contents, but if you can list/highlight the problem in the original answer it will help...

@rstacruz
Copy link

If anyone else is running into this and it doesn't work, note that it only works for lists ("arrays"), not associative arrays. Here's a version for associative arrays:

-- For associative arrays
function object_assign(t1, t2)
	for key, value in pairs(t2) do
	   t1[key] = value
	end 

	return t1
end

-- object_assign({ name = "Miles Davis" }, { genre = "Jazz" })
--> { name = "Miles Davis", genre = "Jazz" } 

@ttii
Copy link

ttii commented Mar 24, 2022

I modify merge table fucntion, very useful~~

for example:
talbe a:
{
[1] = 1,
[2] = 2,
[3] = 3,
[4] = 4,
[5] = 5,
[6] = 6,
[7] = 7,
[8] = 8,
[9] = 9
}
table b:
{
["d"] = 4,
["e"] = {
["z"] = 3,
["x"] = 1,
["y"] = 2
},
[2] = "y",
["a"] = 1,
["b"] = 2,
[1] = "x",
["c"] = 3
}
merge results table:
{
[1] = 1,
[2] = 2,
[3] = 3,
[4] = 4,
[5] = 5,
[6] = 6,
[7] = 7,
[8] = 8,
[9] = 9,
[10] = "y",
[11] = "x",
["d"] = 4,
["e"] = {
["z"] = 3,
["x"] = 1,
["y"] = 2
},
["a"] = 1,
["b"] = 2,
["c"] = 3
}

so cool!, list append, dict add node!

--source:
local function table_merge(...)
    local tables_to_merge = { ... }
    assert(#tables_to_merge > 1, "There should be at least two tables to merge them")

    for k, t in ipairs(tables_to_merge) do
        assert(type(t) == "table", string.format("Expected a table as function parameter %d", k))
    end

    local result = table_clone(tables_to_merge[1])

    for i = 2, #tables_to_merge do
        local from = tables_to_merge[i]
        for k, v in pairs(from) do
            if type(v) == "table" then
                result[k] = result[k] or {}
                assert(type(result[k]) == "table", string.format("Expected a table: '%s'", k))
                result[k] = table_merge(result[k], v)
            elseif type(k) == "string" then
                result[k] = v
            else
                table.insert(result, v)
            end
        end
    end

    return result
end

@dmitrii-eremin
Copy link

TLDR; I understand @dmitrii-eremin that you code helps to clone the contents, but if you can list/highlight the problem in the original answer it will help...

@LRagji Sorry for such a late reply :-)

  • The original code goes only though indexed arrays, not through all table elements.
  • The original code does not clone objects, it just saves a reference to object to other place. So if the original object is changed, then the cloned is changed as well.

@ttii
Copy link

ttii commented Mar 24, 2022

I write a better one! injoin it!

function table_merge(...)
    local tables_to_merge = { ... }
    assert(#tables_to_merge > 1, "There should be at least two tables to merge them")

    for k, t in ipairs(tables_to_merge) do
        assert(type(t) == "table", string.format("Expected a table as function parameter %d", k))
    end

    local result = tables_to_merge[1]

    for i = 2, #tables_to_merge do
        local from = tables_to_merge[i]
        for k, v in pairs(from) do
            if type(k) == "number" then
                table.insert(result, v)
            elseif type(k) == "string" then
                if type(v) == "table" then
                    result[k] = result[k] or {}
                    result[k] = table_merge(result[k], v)
                else
                    result[k] = v
                end
            end
        end
    end

    return result
end

@shaeinst
Copy link

shaeinst commented Apr 2, 2022

function merge_table(table1, table2)
	for _, value in ipairs(table2) do
		table1[#table1+1] = value
	end
	return table1
end

-- example
local table1 = {1, 2, 3}
local table2 = {4, 5, 6}

merged_table = merge_table(table1, table2)
for _, value in ipairs(merged_table) do
	print(value)
end

output
------------------
1
2
3
4
5
6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment