Question

I am trying to join two tables in Lua. Basically, I want to append the contents of one table to the end of the other. I've found lots of code to do this, but it doesn't work when the tables have other tables as values (subtables, I believe they are called?)

I found this question to be similar: Lua - merge tables?

And the code there worked, other than the content in the second table is overwriting the first table. But I do not want the entries in the first table to be overwritten. I just want all the content in the second table to be appended after the content in the first. But I can't figure out how to do that.

So when my first table looks similar to this:

   { Category = 
      { Answer = "String",
        Answer = "String"
      }
   },
   { Category = 
      { Answer = "String",
        Answer = "String"
      }
   }

And my second is the same, I want to end up with:

   { Category = 
      { Answer = "String",
        Answer = "String"
      }
   },
   { Category = 
      { Answer = "String",
        Answer = "String"
      }
   },
   { Category = 
      { Answer = "String",
        Answer = "String"
      }
   },
   { Category = 
      { Answer = "String",
        Answer = "String"
      }
   }

How can this be accomplished?

I am building these tables dynamically from XML files using this code: https://github.com/Cluain/Lua-Simple-XML-Parser

This is my XML file structure:

<?xml version="1.0" encoding="utf-8"?>
<library>
    <gametype1>
        <category name="">
            <answer></answer>
            <answer></answer>
            <answer></answer>
        </category>
        <category name="">
            <answer></answer>
            <answer></answer>
            <answer></answer>
        </category>
    </gametype1>

    <gametype2>
        <category name="">
            <answer></answer>
            <answer></answer>
            <answer></answer>
        </category>
        <category name="">
            <answer></answer>
            <answer></answer>
            <answer></answer>
        </category>
    </gametype2>
</library>

I then load the XML files like such:

gameAnswers1 = xml:loadFile( "file1.xml", system.ResourceDirectory )
gameAnswers2 = xml:loadFile( "file2.xml", system.ResourceDirectory )

gameAnswers1Gametype1 = {}
gameAnswers1Gametype1 = gameAnswers1.library.gametype1

gameAnswers1Gametype2 = {}
gameAnswers1Gametype2 = gameAnswers1.library.gametype2

gameAnswers2Gametype1 = {}
gameAnswers2Gametype1 = gameAnswers2.library.gametype1

gameAnswers2Gametype2 = {}
gameAnswers2Gametype2 = gameAnswers2.library.gametype2

What I would like to do now is concatenate the tables so that I have just one table of gametype1 data and one table of gametype2 data.

And so when I access the table of data by #gameAnswers1Gametype1.category I get the correct number of entries. With the current XML files I am using for testing, file1.xml has 9 category nodes in the gametype1 node and file2.xml has 1 category node in the gametype1 node. So I would expect that when I am done, I will have 10 category nodes in the concatenated table.

(If it matters, I am doing this with the Corona SDK.)

Any help would be most appreciated!

Was it helpful?

Solution

The structure you will receive from the XML lib for each of your two files is something like

{ 
    library = 
    {
        gametype1 =
        {
            category =
            {
                { -- category[1]
                    name="name1",
                    answer = {"ans1", "ans2", "ans3"}
                },
                { -- category[2]
                    name="name2",
                    answer = {"ans1", "ans2", "ans3"}
                },
            }
        },
        gametype2 =
        {
            category =
            {
                { -- category[1]
                    name="name1",
                    answer = {"ans1", "ans2", "ans3"}
                },
                { -- category[2]
                    name="name2",
                    answer = {"ans1", "ans2", "ans3"}
                },
            }
        },
    }
}

and you want to combine table1.library.gametype1 with table2.library.gametype1, and do the same for gametype2 of table1 and table2. Since you will not be changing the two tables after they are created, you don't need deep copy:

local function concat(fromTable, intoTable) 
    local lenFrom = #fromTable
    for i = 1, lenFrom do 
        table.insert(intoTable, fromTable[i])
    end 
end

local gameAnswers1 = xml:loadFile( "file1.xml", system.ResourceDirectory )
local gameAnswers2 = xml:loadFile( "file2.xml", system.ResourceDirectory )

local gameType1A = gameAnswers1.library.gametype1
local gameType1B = gameAnswers2.library.gametype1
concat(gameType1B.category, gameType1A.category)
-- now table contains its categories plus all those of table2
local tableGameType1 = gameType1A 

local gameType2A = gameAnswers1.library.gametype2
local gameType2B = gameAnswers2.library.gametype2
concat(gameType2B.category, gameType2A.category)
-- now table1 contains its categories plus all those of table2
local tableGameType2 = gameType2A 

Just beware that gameAnswers1 now contains all categories from both files.

OTHER TIPS

Non-destructively concatenate multiple tables:

function table.concat(...)
  local r, n, t = {}, 1, {...}
  for i = 1, select('#', ...) do
    local t = t[i]
    if t then
      for i = 1, #t do
        r[n], n = t[i], n + 1
      end
    end
  end
end

This solution allows concatenating a table with itself, as well as ignoring additional hash-keys and omitted tables.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top