65

ORIGINAL POST

Given that there is no built in function in Lua, I am in search of a function that allows me to append tables together. I have googled quite a bit and have tried every solutions I stumbled across but none seem to work properly.

The scenario goes like this: I am using Lua embeded in an application. An internal command of the application returns a list of values in the form of a table.

What I am trying to do is call that command recursively in a loop and append the returned values, again in the form of a table, to the table from previous iterations.


EDIT

For those who come across this post in the future, please note what @gimf posted. Since Tables in Lua are as much like arrays than anything else (even in a list context), there is no real correct way to append one table to another. The closest concept is merging of tables. Please see the post, "Lua - merge tables?" for help in that regard.

5
  • Possible dupe: stackoverflow.com/questions/1283388/lua-merge-tables. You mention "recursivly in a loop". Do you search for a deep-copy + merge? Commented Sep 11, 2009 at 14:00
  • The following are the links I found that offered solutions: ardoris.wordpress.com/2008/08/10/… idevgames.com/forum/archive/index.php/t-10223.html Though I understand the approach of each, neither seem to work. Do you have a working solution? Commented Sep 11, 2009 at 15:09
  • gimpf, maybe I am not being completely clear. Merging tables and concatinating tables are similar but very different. I am interested in appending one table to another, thus the use of the word concatenate. Commented Sep 11, 2009 at 15:16
  • Please see my edit; an example of what you want to do in the form of 3 lua tables (2 in, 1 out) would be very helpful. Commented Sep 11, 2009 at 18:19
  • BTW, I think it's better called join, since lua has a built-in function table.concat(), which concat values of 1 single table as a single string. Commented Sep 15, 2024 at 15:40

16 Answers 16

42

Overcomplicated answers much?

Here is my implementation:

function TableConcat(t1,t2)
    for i=1,#t2 do
        t1[#t1+1] = t2[i]
    end
    return t1
end
Sign up to request clarification or add additional context in comments.

13 Comments

wouldn't ipairs iteration with table.insert be better (more readable and/or faster)?
ipairs is barely more costly than normal, the reason not to use it is it doesn't guarantee order of items in the table. the reason not to use insert is it's dramatically more costly than a standard index set on a table, because insert will call a routine that pushes values in the table back from the index it was called on, while there are no values past [#t+1], the routine is still called, causing a performance issue, on a compiled language, there is no difference, but using an interpreted language, we have to be careful what all we ask the computer to do for us
From what i know, ipairs guarantees iteration order be for i=1 ... till the first t[i]==nil, no? Which for non-degenerate cases is same as for i=1,#t. Re insert vs indexing set though, you are right - i measured and there is 5-6x performance difference
NB: ipairs ~= pairs. There is a reason for the "i". pairs is disorderly, ipairs isn't
Shouldn't the third line be t1[#t1+i] = t2[i]?
|
39

If you want to concatenate an existing table to a new one, this is the most concise way to do it:

local t = {3, 4, 5}
local concatenation = {1, 2, table.unpack(t)}

Although I'm not sure how good this is performance-wise.

2 Comments

Just note that this only work if table.unpack is the last argument (unlike Python's *t or JavaScript's ...t), see stackoverflow.com/questions/37372182/…
As an addition, for LuaJIT 5.1 the param position is flexible. (Using it in Neovim configuration)
18

And one more way:

for _,v in ipairs(t2) do 
    table.insert(t1, v)
end

It seems to me the most readable one - it iterates over the 2nd table and appends its values to the 1st one, end of story. Curious how it fares in speed to the explicit indexing [] above

1 Comment

Does not work for t1={a={1},2} t2={3,d={4}}
8

A simple way to do what you want:

local t1 = {1, 2, 3, 4, 5}
local t2 = {6, 7, 8, 9, 10}

local t3 = {unpack(t1)}
for I = 1,#t2 do
    t3[#t1+I] = t2[I]
end

4 Comments

why the {unpack(t1)} ?! all it does i make copy of t1 but question implied updating in-place?
@NasBanov He asked how to concatenate. When you concatenate strings you get a new string. I assumed he wanted something like that.
hmm, you are right regarding the word "concatenation" in the title. But the question speaks about "appending", which is a mutator. Still { unpack(tbl) } is a neat trick for cloning a table - with limitations (something like 1M elements)
@NasBanov However this contradiction in terms is the questioner's fault, so I see accepting either answer as valid and correct is fine.
5

To add two tables together do this

    ii=0
for i=#firsttable, #secondtable+#firsttable do
    ii=ii+1
    firsttable[i]=secondtable[ii]
end

use the first table as the variable you wanted to add as code adds the second one on to the end of the first table in order.

  • i is the start number of the table or list.
  • #secondtable+#firsttable is what to end at.

It starts at the end of the first table you want to add to, and ends at the end of the second table in a for loop so it works with any size table or list.

1 Comment

This is wrong. You have to start with i=(#firsttable+1), or you will munch over the last element in the first table. In case of the first table being empty you will even try to access firsttable[0], but arrays are indexed starting with 1 in lua.
4

In general the notion of concatenating arbitrary tables does not make sense in Lua because a single key can only have one value.

There are special cases in which concatenation does make sense. One such is for tables containing simple arrays, which might be the natural result of a function intended to return a list of results.

In that case, you can write:

-- return a new array containing the concatenation of all of its 
-- parameters. Scalar parameters are included in place, and array 
-- parameters have their values shallow-copied to the final array.
-- Note that userdata and function values are treated as scalar.
function array_concat(...) 
    local t = {}
    for n = 1,select("#",...) do
        local arg = select(n,...)
        if type(arg)=="table" then
            for _,v in ipairs(arg) do
                t[#t+1] = v
            end
        else
            t[#t+1] = arg
        end
    end
    return t
end

This is a shallow copy, and makes no attempt to find out if a userdata or function value is a container or object of some kind that might need different treatment.

An alternative implementation might modify the first argument rather than creating a new table. This would save the cost of copying, and make array_concat different from the .. operator on strings.

Edit: As observed in a comment by Joseph Kingry, I failed to properly extract the actual value of each argument from .... I also failed to return the merged table from the function at all. That's what I get for coding in the answer box and not testing the code at all.

3 Comments

+1 on the notion for "natural result of a function ... return a list of results". This is quite probable.
I think there is an error in this function, I think you need another select in there after the for to get the actual value out of .... lua-users.org/wiki/VarargTheSecondClassCitizen See Issue 8
Yup. Apparently I didn't test this code before posting, or that defect would have been obvious. More obvious in hindsight is the missing return t before the last end.
2

If you want to merge two tables, but need a deep copy of the result table, for whatever reason, use the merge from another SO question on merging tables plus some deep copy code from lua-users.

(edit Well, maybe you can edit your question to provide a minimal example... If you mean that a table

 { a = 1, b = 2 }

concatenated with another table

{ a = 5, b = 10 }

should result in

{ a = 1, b = 2, a = 5, b = 10 }

then you're out of luck. Keys are unique.

It seems you want to have a list of pairs, like { { a, 1 }, { b, 2 }, { a, 5 }, { b, 10 } }. You could also use a final structure like { a = { 1, 5 }, b = { 2, 10 } }, depending on your application.

But the simple of notion of "concatenating" tables does not make sense with Lua tables. )

2 Comments

gimf, you were right. I was misinterpreting the use of lists in Tables to think that they could simply be concatenated. Further testing led me to the conclusion that what I really needed to be doing was a merge. Thank you for your help and patience with a Lua newbie.
@John, we were all newbies once... coming from complex languages, it is sometimes surprising how much power is hiding inside Lua's simplicity. It can take a while to grok it.
2

Here is an implementation I've done similar to RBerteig's above, but using the hidden parameter arg which is available when a function receives a variable number of arguments. Personally, I think this is more readable vs the select syntax.

function array_concat(...)
    local t = {}

    for i = 1, arg.n do
        local array = arg[i]
        if (type(array) == "table") then
            for j = 1, #array do
                t[#t+1] = array[j]
            end
        else
            t[#t+1] = array
        end
    end

    return t
end

Comments

1

Here is my implementation to concatenate a set of pure-integer-indexing tables, FYI.

  1. define a function to concatenate two tables, concat_2tables
  2. another recursive function concatenateTables: split the table list by unpack, and call concat_2tables to concatenate table1 and restTableList

    t1 = {1, 2, 3}
    t2 = {4, 5}
    t3 = {6}
    
    concat_2tables = function(table1, table2)
        len = table.getn(table1)
        for key, val in pairs(table2)do
            table1[key+len] = val
        end
        return table1
    end
    
    concatenateTables = function( tableList )
        if tableList==nil then
            return  nil
        elseif table.getn(tableList) == 1 then
            return  tableList[1]
        else
            table1 = tableList[1]
            restTableList = {unpack(tableList, 2)}
            return concat_2tables(table1, concatenateTables(restTableList))
        end
    end
    
    tt = {t1, t2, t3}
    t = concatenateTables(tt)  
    

Comments

1

EDIT


Here's a better solution, the other one tended to overwrite numeric keys, the usage is still the same:

function merge(...)
  local temp = {}
  local index = 1
  local result = {}
  
  math.randomseed(os.time())

  for i, tbl in ipairs({ ... }) do
    for k, v in pairs(tbl) do
      if type(k) == 'number' then
        -- randomize numeric keys
        k = math.random() * i * k
      end
      
      temp[k] = v
    end
  end
  
  for k, v in pairs(temp) do
    if type(k) == "number" then
      -- Sort numeric keys into order
      if result[index] then
        index = index + 1
      end
      
      k = index
    end
    
    result[k] = v
  end

  return result
end

ORIGINAL


A wee bit late to the game, but this seems to work for me:

function concat(...)
  local result = {}
  
  for i, tbl in ipairs({...}) do
    for k, v in pairs(tbl) do
      if type(k) ~= "number" then
        result[k] = v
      else
        result[i] = v
      end
    end
  end
  
  return result
end

It might be a bit overcomplicated, but it takes an infinite amount of arguments, and works for both key-value pairs and regular "arrays" (numbers as keys). Here's an example

2 Comments

This is the only solution that worked for tables with key/indexes t1={a={a=1}, b=2, 5} t2={c={c=3}, d=4, 6}
However note that it doesn't maintain the order of the elements in the table when merging them together.
1

The other solutions here suffered from 3 issues:

  1. Did not work with tables that contain key/values
  2. Didn't maintain the order of the elements in the tables while merging
  3. Did not work with tables with mixed numeric indices and key based indices

This solution is a variant of the original solution proposed by @kaptcha which addresses the shortcomings noted above:

--- Function to merge/join tables
--- @param ... table List of tables to be merged
--- @return table Merged table
function MergeTables(...)
    local result = {}

    for i, tbl in ipairs({...}) do
      for k, v in pairs(tbl) do
        if type(k) ~= "number" then
          result[k] = v
        else
          table.insert(result, v)
        end
      end
    end

    return result
end

Usage:

local t1 = { a={1}, b={b=2} }
local t2 = { c={3}, d={d=4} }
local tMerged = MergeTables(t1, t2)

Comments

0
-- Lua 5.1+
function TableAppend(t1, t2)
    -- A numeric for loop is faster than pairs, but it only gets the sequential part of t2
    for i = 1, #t2 do
        t1[#t1 + 1] = t2[i] -- this is slightly faster than table.insert
    end

    -- This loop gets the non-sequential part (e.g. ['a'] = 1), if it exists
    local k, v = next(t2, #t2 ~= 0 and #t2 or nil)
    while k do
        t1[k] = v -- if index k already exists in t1 then it will be overwritten
        k, v = next(t2, k)
    end
end

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
0

I like the simplicity in @Weeve Ferrelaine answer, but mutations may cause many issues and in general, are not desirable.

Version with NO MUTATION.
---@param t1 {}
---@param t2 {}
function TableConcat(t1,t2)
    local tOut = {}

    for i = 1, #t1 do
        tOut[i] = t1[i]
    end

    for i = #t1, #t1 + #t2 do
        tOut[i] = t2[i]
    end

    return tOut
end
Original implementation, that's mutating t1.
function TableConcat(t1,t2)
    for i=1,#t2 do
        t1[#t1+1] = t2[i]
    end
    return t1
end

Comments

0

use table.insert() function

table1 = {
  "param1=value1",
  "param2=value2",
  "param3=value3"
}
table2 = {
  "param21=value1",
  "param23=value2",
  "param23=value3"
}
table.insert(table1, table.concat(table2, ","))
print(table.unpack(table1));

Comments

0

My approach on concatenating tables

local table_fuse = function (...)
    local result = {}
    local i = 1

    for _, obj in next, {...} do
        if type(obj) ~= "table" then
            result[i] = obj
            i = i + 1
        else
            for k, v in next, obj do
                if type(k) ~= "number" then
                    result[k] = v
                else
                    result[i] = v
                    i = i + 1
                end
            end
        end
    end

    return result
end

You can pass tables and non-table objects and it will happily merge them into one table. Example:

local ex_1 = {1, 66, "hello", {"333", 41}}
local ex_2 = {"test_1", "another test"}
ex_2[":33"] = "i have no idea what to put here"
ex_2["UwU OwO"] = 1337
local ex_3 = 12345

local tbl = table_fuse(
    {"foo", "bar"}, ex_1, ex_2, "something",
    {"another something", "aaaa"}, ex_3,
    "haii :3", {{123, "123"}}
)

print(inspect(tbl)) -- github.com/kikito/inspect.lua

-- { "foo", "bar", 1, 66, "hello", { "333", 41 }, "test_1", "another test", "something", "another something", "aaaa", 12345, "haii :3", { 123, "123" },
--   [":33"] = "i have no idea what to put here",
--   ["UwU OwO"] = 1337
-- }

Comments

0

There are a lot of working solutions here, but here is the fastest one in terms of performance:

function table.append(t1, t2)
  local n = #t1
  for i = 1, #t2 do
    t1[n + i] = t2[i]
  end
  return t1
end

Concatenates in place Table t2 at the end of Table t1.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.