2009-09-11 38 views
25

原帖級聯表

由於存在在Lua功能沒有內置,我在尋找一個可以讓我追加表一起的。我搜索了很多,並嘗試了我偶然發現的所有解決方案,但沒有一個能夠正常工作。

這種情況是這樣的:我在應用程序中使用Lua嵌入。應用程序的內部命令以表格的形式返回值列表。

我想要做的是在循環中遞歸調用該命令,並將返回的值再次以表格的形式附加到以前迭代的表中。


編輯

對於那些誰遇到這個職位在未來,請注意什麼@gimf公佈。由於Lua中的表與數組一樣多(甚至在列表上下文中),所以沒有真正的將一個表附加到另一個表的正確方法。最接近的概念是合併表格。請查看帖子「Lua - merge tables?」尋求這方面的幫助。

+0

可能欺騙:http://stackoverflow.com/questions/1283388/lua-merge-tables。 你提到「循環中的遞歸」。你搜索一個深度複製+合併? – gimpf 2009-09-11 14:00:45

+0

以下是我發現提供的解決方案的鏈接: http://ardoris.wordpress.com/2008/08/10/lua-merge-two-tables-awesome3-rc2-config/ http:// www.idevgames.com/forum/archive/index.php/t-10223.html 雖然我理解每種方法,但似乎都不起作用。你有沒有工作解決方案? – 2009-09-11 15:09:17

+0

gimpf,也許我不完全清楚。合併表格和合並表格是相似的,但是非常不同。我有興趣將一個表追加到另一個表中,因此使用了concatenate這個詞。 – 2009-09-11 15:16:07

回答

2

如果您想要合併兩個表,但需要結果表的深層副本,無論出於何種原因,請使用another SO question on merging tables合併加上來自lua-users的一些深度複製代碼。

(編輯 好吧,也許你可以編輯你的問題提供了一個小例子...如果你的意思是一臺

{ a = 1, b = 2 } 

串聯與另一個表

{ a = 5, b = 10 } 

應導致

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

那麼你的運氣不好。 鑰匙是獨一無二的。

看來你想擁有一個配對清單,如{ { a, 1 }, { b, 2 }, { a, 5 }, { b, 10 } }。您也可以使用像{ a = { 1, 5 }, b = { 2, 10 } }這樣的最終結構,具體取決於您的應用程序。

但是,「連接」表的簡單概念與Lua表沒有任何意義。

+0

gimf,你是對的。我誤解了表中列表的使用,認爲它們可以簡單地連接起來。進一步的測試讓我得出結論,我真正需要做的是合併。感謝您對Lua新手的幫助和耐心。 – 2009-09-12 03:17:41

+1

@John,我們都是新手......來自複雜的語言,有時令人驚訝的是Lua的簡單性隱藏着多少權力。它可能需要一段時間來訓練它。 – RBerteig 2009-09-12 18:06:29

4

一般來說,連接任意表的概念在Lua中沒有意義,因爲單個鍵只能有一個值。

有些特殊情況下級聯確實有意義。其中之一就是包含簡單數組的表格,這可能是返回結果列表的函數的自然結果。

在這種情況下,你可以寫:

 
-- return a new array containing the concatenation of all of its 
-- parameters. Scaler 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 

這是一個淺拷貝,並沒有試圖找出一個userdata或函數值,可能需要不同的某種類型的容器或對象治療。

另一種實現可能會修改第一個參數,而不是創建一個新表。這樣可以節省複製的成本,並且使得array_concat..運算符在字符串上不同。

編輯:正如Joseph Kingry在評論觀察,我沒能正確地從...提取每個參數的實際值。我也沒有從函數返回合併表。這就是我在答案框中編寫代碼而不是測試代碼。

+0

對「功能的自然結果...返回結果列表」的概念+1。這很可能。 – gimpf 2009-09-12 07:44:39

+0

我認爲在這個函數中有一個錯誤,我認爲在'for'後面需要另一個'select'來從'...'中得到實際值。 http://lua-users.org/wiki/VarargTheSecondClassCitizen請參閱第8期 – 2010-03-03 17:30:50

+1

是的。顯然,我沒有在發佈之前測試這個代碼,或者那個缺陷會很明顯。事後看來更明顯的是在最後一個「結束」之前缺少「return t」。 – RBerteig 2010-03-04 23:01:51

1

這裏是我已經完成的類似於上面的RBerteig的實現,但是使用隱藏參數arg當函數接收到可變數量的參數時可用。就個人而言,我認爲這比選擇語法更具可讀性。

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 
5

將兩個表一起做這個

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

使用第一個表,你想添加的代碼,從而增加了到第一個表的末尾第二個變量。

  • i是表或列表的開始編號。
  • #secondtable+#firsttable是什麼結束。

它開始於要添加到第一個表的末尾,因此它與任何尺寸表或列表工作在二表在for循環末尾。

+0

這是錯誤的。您必須以i =(#firsttable + 1)開頭,否則您將在第一個表格的最後一個元素上進行切換。在第一個表爲空的情況下,您甚至會嘗試訪問firsttable [0],但數組在lua中以1開頭索引。 – scravy 2013-08-21 17:16:34

24

過於複雜的答案很多?

這裏是我的實現:

function TableConcat(t1,t2) 
    for i=1,#t2 do 
     t1[#t1+1] = t2[i] 
    end 
    return t1 
end 
+0

不會''與'table.insert' ipairs'迭代更好(更可讀和/或更快)? – 2015-03-20 23:29:46

+0

ipairs比平時貴很多,不使用它的原因是它不能保證表中項目的順序。不使用插入的原因是它比表中的標準索引成本高得多,因爲插入將調用一個例程,它將表中的值從它被調用的索引中推回,而沒有值過去[#t +1],例程仍然被調用,導致性能問題,在編譯語言上沒有區別,但是使用解釋型語言,我們必須小心我們要求計算機爲我們做的所有事情 – 2015-03-22 17:44:46

+4

From what i知道,'ipairs'保證迭代次序是'for i = 1' ...直到第一個t [i] == nil,no?對於非退化情況,與'for i = 1,#t'相同。 雖然重新'插入'與索引設置,你是對的 - 我測量,並有5-6倍的性能差異 – 2015-03-22 18:41:00

3

一個簡單的方法做你想要的:

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 
+0

爲什麼'{unpack(t1)}'?!所有它我做't1'的副本,但問題暗示更新就地? – 2015-03-20 23:22:13

+1

@NasBanov他問如何連接。當你連接字符串時,你會得到一個新的字符串。我以爲他想要那樣的東西。 – warspyking 2015-12-07 11:34:42

+1

嗯,對於標題中的「連接」這個詞你是對的。但是這個問題提到了「追加」,這是一個變種。仍然'{unpack(tbl)}'是克隆表的一個巧妙的技巧 - 有限制(類似於1M元素) – 2015-12-08 22:21:39

2

而另一種方式:

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

在我看來,最可讀的 - 它遍歷第二個表並將它的值附加到第一個,即故事結束。好奇它如何在速度上明確索引[]以上

1

這裏是我的實現連接一組純粹的整數索引表,FYI。

  1. 定義一個函數來連接兩個表,concat_2tables
  2. 另一個遞歸函數concatenateTables:由unpack拆表清單和通話concat_2tables來連接table1restTableList

    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)