Lua 中的表串联

发布于 2024-08-04 01:34:38 字数 466 浏览 7 评论 0原文

原始帖子

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

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

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


编辑

对于那些将来看到这篇文章的人,请注意@gimf 发布的内容。由于 Lua 中的表比其他任何东西都更类似于数组(即使在列表上下文中),因此没有真正正确的方法将一个表附加到另一个表。最接近的概念是表的合并。请参阅帖子“Lua - 合并表?”以获取这方面的帮助。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

雅心素梦 2024-08-11 01:34:38

答案过于复杂了很多吗?

这是我的实现:

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

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
音栖息无 2024-08-11 01:34:38

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

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

尽管我不确定这在性能方面有多好。

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.

我ぃ本無心為│何有愛 2024-08-11 01:34:38

还有一种方式:

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

在我看来,这是最具可读性的一种方式 - 它迭代第二个表并将其值附加到第一个表,即故事的结尾。好奇它的速度与上面的显式索引 [] 相比如何

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

朱染 2024-08-11 01:34:38

一个简单的方法来做你想做的事:

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

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
柒七 2024-08-11 01:34:38

要将两个表添加在一起,请

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

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

  • i 是表或列表的起始编号。
  • #secondtable+#firsttable 是结束的地方。

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

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.

浅听莫相离 2024-08-11 01:34:38

一般来说,连接任意表的概念在 Lua 中没有意义,因为单个键只能有一个值。

在某些特殊情况下,串联确实有意义。其中之一是包含简单数组的表,这可能是旨在返回结果列表的函数的自然结果。

在这种情况下,您可以这样写:

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

这是一个浅拷贝,并且不会尝试找出userdata 或函数值是否是可能需要不同处理的某种容器或对象。

另一种实现可能会修改第一个参数而不是创建新表。这将节省复制成本,并使 array_concat 与字符串上的 .. 运算符不同。

编辑:正如 Joseph Kingry 的评论中所观察到的,我未能正确提取... 中每个参数的实际值。我也根本无法从函数返回合并表。这就是我在答案框中编码而不测试代码所得到的结果。

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.

尝蛊 2024-08-11 01:34:38

如果您想合并两个表,但需要结果表的深层副本,无论出于何种原因,请使用 中的合并另一个关于合并表的问题以及来自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 表来说没有意义。
)

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.
)

笑,眼淚并存 2024-08-11 01:34:38

这是我完成的与上面的 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

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
灼痛 2024-08-11 01:34:38

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

  1. 定义一个连接两个表的函数,concat_2tables
  2. 另一个递归函数concatenateTables:通过unpack拆分表列表,并调用concat_2tables 连接 table1restTableList

    <前><代码>t1 = {1, 2, 3}
    t2 = {4, 5}
    t3 = {6}

    concat_2tables = 函数(表1, 表2)
    len = 表.getn(表1)
    对于 key,val 成对(table2)do
    表1[键+长度] = val
    结尾
    返回表1
    结尾

    concatenateTables = 函数( 表列表 )
    如果 tableList==nil 那么
    返回零
    elseif table.getn(tableList) == 1 那么
    返回表列表[1]
    别的
    表1 = 表列表[1]
    RestTableList = {解压(tableList, 2)}
    返回 concat_2tables(table1, concatenateTables(restTableList))
    结尾
    结尾

    tt = {t1, t2, t3}
    t = 连接表(tt)

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)  
    
甜味拾荒者 2024-08-11 01:34:38

编辑


这是一个更好的解决方案,另一个倾向于覆盖数字键,用法仍然相同:

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


游戏有点晚了,但这似乎对我有用:

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

它可能有点过于复杂,但它需要无限量的参数,并且适用于键值对和常规“数组”(数字作为键)。这是一个示例

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

烟织青萝梦 2024-08-11 01:34:38

这里的其他解决方案遇到了 3 个问题:

  1. 不适用于包含键/值的表 合并
  2. 时未维护表中元素的顺序
  3. 不适用于具有混合数字索引和基于键的索引的表

该解决方案是@kaptcha 提出的原始解决方案的变体,它解决了上述缺点:

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

用法:

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

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)
别闹i 2024-08-11 01:34:38
-- 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
-- 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
冰雪梦之恋 2024-08-11 01:34:38

我喜欢 @Weeve Ferrelaine 答案的简单性,但突变可能会导致许多问题总的来说都是不可取的。

没有突变的版本。
---@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
原始实现,即改变 t1。
function TableConcat(t1,t2)
    for i=1,#t2 do
        t1[#t1+1] = t2[i]
    end
    return t1
end

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
兮颜 2024-08-11 01:34:38

使用 table.insert() 函数

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

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));
平定天下 2024-08-11 01:34:38

我连接表的方法

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

您可以传递表和非表对象,它会很乐意将它们合并到一个表中。
例子:

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
-- }

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
-- }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文