Lua中的表连接

Posted

技术标签:

【中文标题】Lua中的表连接【英文标题】:Concatenation of tables in Lua 【发布时间】:2010-11-27 12:10:04 【问题描述】:

原帖

鉴于 Lua 中没有内置函数,我正在寻找一个允许我将表附加在一起的函数。我用谷歌搜索了很多,并尝试了我偶然发现的所有解决方案,但似乎没有一个能正常工作。

场景是这样的:我正在使用嵌入在应用程序中的 Lua。应用程序的内部命令以表格的形式返回值列表。

我要做的是在循环中递归调用该命令,并将返回的值(再次以表格的形式)附加到先前迭代的表格中。


编辑

对于以后遇到此帖子的人,请注意@gimf 发布的内容。由于 Lua 中的表比其他任何东西都更像数组(即使在列表上下文中),所以没有真正正确的方法可以将一个表附加到另一个表。最接近的概念是合并表。有关这方面的帮助,请参阅帖子“Lua - merge tables?”。

【问题讨论】:

可能的欺骗:***.com/questions/1283388/lua-merge-tables。您提到“循环递归”。您是否搜索深拷贝 + 合并? 以下是我发现的提供解决方案的链接:ardoris.wordpress.com/2008/08/10/… idevgames.com/forum/archive/index.php/t-10223.html 虽然我了解每种方法,但似乎都不起作用。您有可行的解决方案吗? gimpf,也许我不是很清楚。合并表和连接表相似但非常不同。我有兴趣将一个表附加到另一个表,因此使用了 concatenate 这个词。 请看我的编辑;以 3 个 lua 表(2 进 1 出)的形式举例说明您想要做的事情会非常有帮助。 【参考方案1】:

如果您想合并两个表,但需要一个结果表的深拷贝,无论出于何种原因,请使用来自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 表没有意义。 )

【讨论】:

gimf,你是对的。我误解了 Tables 中列表的使用,认为它们可以简单地连接起来。进一步的测试使我得出结论,我真正需要做的是合并。感谢您对 Lua 新手的帮助和耐心。 @John,我们曾经都是新手......来自复杂的语言,有时令人惊讶的是 Lua 的简单性中隐藏着多少力量。摸索它可能需要一段时间。【参考方案2】:

一般来说,连接任意表的概念在 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 的评论中所观察到的,我未能正确地从... 中提取每个参数的实际值。我也根本没有从函数中返回合并表。这就是我在答案框中编码而不是测试代码所得到的结果。

【讨论】:

+1 关于“函数的自然结果......返回结果列表”的概念。这很有可能。 我认为这个函数有错误,我认为你需要在for 之后再添加一个select 才能从... 中获取实际值。 lua-users.org/wiki/VarargTheSecondClassCitizen 见第 8 期 是的。显然我在发布之前没有测试这段代码,否则这个缺陷会很明显。事后看来,更明显的是在最后一个end 之前缺少return t【参考方案3】:

这是我所做的与上面 Rberteig 类似的实现,但使用了隐藏参数 arg,当函数接收可变数量的参数时,该参数可用。就个人而言,我认为这比 select 语法更具可读性。

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

【讨论】:

【参考方案4】:

要将两个表添加在一起,请执行此操作

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

使用第一个表作为要添加的变量,因为代码会将第二个表按顺序添加到第一个表的末尾。

i 是表格或列表的起始编号。 #secondtable+#firsttable 是结尾。

它从您要添加到的第一个表的末尾开始,并在 for 循环中的第二个表的末尾结束,因此它适用于任何大小的表或列表。

【讨论】:

这是错误的。您必须从 i=(#firsttable+1) 开始,否则您将咀嚼第一个表中的最后一个元素。如果第一个表为空,您甚至会尝试访问 firsttable[0],但数组在 lua 中从 1 开始索引。【参考方案5】:

答案过于复杂?

这是我的实现:

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

【讨论】:

ipairs 迭代与table.insert 会不会更好(更具可读性和/或更快)? ipairs 的成本几乎没有比正常的高,不使用它的原因是它不能保证表中项目的顺序。不使用 insert 的原因是它比在表上设置的标准索引成本高得多,因为 insert 将调用一个例程,将表中的值从调用它的索引推回,而没有超过 [#t +1],该例程仍然被调用,导致性能问题,在编译语言上,没有区别,但是使用解释语言,我们必须小心我们要求计算机为我们做的所有事情 据我所知,ipairs 保证迭代顺序为for i=1 ...直到第一个 t[i]==nil,不是吗?对于非退化情况与for i=1,#t 相同。回复 insert 与索引集虽然,你是对的 - 我测量了,有 5-6 倍的性能差异 注意:ipairs ~= pairs。 “我”是有原因的。 pairs 是无序的,ipairs 不是 第三行不应该是t1[#t1+i] = t2[i]吗?【参考方案6】:

做你想做的事的简单方法:

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

【讨论】:

为什么是unpack(t1)?!我所做的一切都是复制t1,但问题暗示就地更新? @NasBanov 他问如何连接。当您连接字符串时,您会得到一个新字符串。我以为他想要那样的东西。 嗯,您对标题中的“连接”一词是正确的。但问题是关于“附加”,它是一个突变体。仍然 unpack(tbl) 是克隆表的巧妙技巧 - 有限制(例如 1M 元素) @NasBanov 然而,这种矛盾是提问者的错,所以我认为接受任何一个答案都是有效和正确的。【参考方案7】:

还有一种方法:

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

在我看来,它是最易读的——它遍历第二个表并将其值附加到第一个表,故事的结尾。好奇它对上面的显式索引 [] 的速度如何

【讨论】:

【参考方案8】:

这是我连接一组纯整数索引表的实现,仅供参考。

    定义一个函数来连接两个表,concat_2tables

    另一个递归函数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)  
    

【讨论】:

【参考方案9】:

如果要将现有表连接到新表,这是最简洁的方法:

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

虽然我不确定这在性能方面有多好。

【讨论】:

请注意,这仅在 table.unpack 是最后一个参数时才有效(与 Python 的 *tjavascript...t 不同),请参阅 ***.com/questions/37372182/…【参考方案10】:
-- 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

【讨论】:

您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。【参考方案11】:

使用 table.concat:

http://lua-users.org/wiki/TableLibraryTutorial

> = table.concat( 1, 2, "three", 4, "five" )
12three4five
> = table.concat( 1, 2, "three", 4, "five" , ", ")
1, 2, three, 4, five
> = table.concat( 1, 2, "three", 4, "five" , ", ", 2)
2, three, 4, five
> = table.concat( 1, 2, "three", 4, "five" , ", ", 2, 4)
2, three, 4

【讨论】:

以上是关于Lua中的表连接的主要内容,如果未能解决你的问题,请参考以下文章

如何将 MySQL 中的表与 Oracle 中的表连接起来

在两个不同数据库中的表之间连接?

带有 TIMESTAMP 的 SQL Server 中的表连接问题

MYSQL中的表的连接方式都有哪些,各有些啥特点?

使用 ETL 中的表连接更改数据捕获

SparkSQL 中的表连接顺序以获得更好的性能