如何获取 Lua 表中的条目数?

Posted

技术标签:

【中文标题】如何获取 Lua 表中的条目数?【英文标题】:How to get number of entries in a Lua table? 【发布时间】:2011-02-11 22:39:12 【问题描述】:

听起来像是一个“让我为你搜索”的问题,但不知何故我找不到答案。 Lua # 运算符只计算带有整数键的条目,table.getn 也是如此:

tbl = 
tbl["test"] = 47
tbl[1] = 48
print(#tbl, table.getn(tbl))   -- prints "1     1"

count = 0
for _ in pairs(tbl) do count = count + 1 end
print(count)            -- prints "2"

如何在不计算的情况下获得所有个条目的数量?

【问题讨论】:

@lhf:我编写了一个序列化程序,它会记住它看到的每个对象,并且下次看到它时它会发出一个整数引用而不是对象。写这个的自然方式类似于dictionary[value] = #dictionary + 1,其中# 表示所有对象的数量。 想知道为什么你想要这个:在所有 sane 用例中#(参见 kaizer.se 的回答),所有对象的计数完全等于 # 已经返回的;似乎让 #count everything 严格来说是一种改进。当然,我是 Lua 新手,可能没有抓住重点。 @lhf 另一个使用示例:将大量数据检索到一个表中,其中每个数据项都有一个唯一的字符串标识符。我使用这个标识符作为键,因为我稍后会用它来查找。我现在想打印处理的数据项的数量。我必须保留一个计数器并为每一行手动增加它。当然不是什么大不了的事,但不数数就不能说出这样的事情是不寻常的,因为你问“为什么”...... :) 当用作容器时,该表是保存有关当前对象计数信息的最佳位置。例如,当表格用作 Set 时。 @lhf:我还有一个用例,我需要知道数字,在这种情况下,我需要知道表格中是否只剩下一个项目,在这种情况下我会处理它与如果有很多项目不同。如果答案是我们计算它们,那很好;我猜一个刚刚得到答案的函数会降低我们在其他地方的性能(这样的功能可能需要 lua 每次我们设置表值时都测试新旧值是否为 nil,然后相应地更新计数器) @Alternator,要测试表中是否正好有一对,请使用next(t)~=nil and next(next(t))==nil 【参考方案1】:

您已经有了问题中的解决方案——唯一的方法是使用pairs(..) 迭代整个表。

function tablelength(T)
  local count = 0
  for _ in pairs(T) do count = count + 1 end
  return count
end

另外,请注意“#”运算符的定义比这要复杂一些。让我通过这张表来说明这一点:

t = 1,2,3
t[5] = 1
t[9] = 1

根据手册,任何 3、5 和 9 都是#t 的有效结果。使用它的唯一明智的方法是使用一个没有 nil 值的连续部分的数组。

【讨论】:

好吧,他说“不计算它们”,但可能没有其他办法 According to the manual, any of 3, 5 and 9 are valid results for #t。根据手册,在非序列上调用 # 是 undefined。这意味着 any 结果 (-1, 3, 3.14, 5, 9) 是有效的。 关于有效结果:u0b34a0f6ae 对于 Lua 5.1 是正确的,而 cubuspl42 对于 Lua 5.2 是正确的。无论哪种情况,整个事情都是完全疯狂的。 最好有一个基于reduce的基本fp实用程序:github.com/sarimarton/.config/blob/master/hammerspoon/util/…【参考方案2】:

您可以设置一个元表来跟踪条目的数量,如果经常需要此信息,这可能比迭代更快。

【讨论】:

有没有一种方便的方法来处理使用这种方法擦除条目? 遗憾的是,除非索引不存在,否则 __newindex 函数似乎不会在 nil 分配上触发,因此您似乎必须通过特殊函数来删除条目。 您应该将数据存储在单独的表中(例如可作为 __index 和 __newindex 的上值访问)。然后 __index 和 __newindex 都会为每个表访问触发。不过,您应该检查性能是否可以接受。 @Alexander:啊,是的,然后是下一个绊脚石:如果您代理表,那么按对的正常迭代不起作用。听说这可以在 Lua 5.2 中解决。 在 5.2 中会有 __pairs 和 __ipairs 元方法......如果你想在 5.1 中这样做,你必须用你自己的替换 pairs() 函数。但这可能太多了。 :-)【参考方案3】:

我所知道的获取表中条目数的最简单方法是使用“#”。 #tableName 获取条目的数量,只要它们被编号:

tbl=
    [1]
    [2]
    [3]
    [4]
    [5]

print(#tbl)--prints the highest number in the table: 5

遗憾的是,如果它们没有编号,它将无法正常工作。

【讨论】:

【参考方案4】:

有一种方法,但可能会令人失望:使用附加变量(或表的字段之一)来存储计数,并在每次插入时增加它。

count = 0
tbl = 

tbl["test"] = 47
count = count + 1

tbl[1] = 48
count = count + 1

print(count)   -- prints "2"

别无他法,# 运算符仅适用于具有连续键的类数组表。

【讨论】:

这可以通过代理表和元方法自动化,正如ergosys's answer所提到的那样 我从 cmets 得到的印象是 proxytable/metamethods 东西还不完全支持这种情况,所以我会接受这是目前可用的最佳方式。 计数是表格的唯一方法,在创建表格时添加行比每次需要计数时都计数的函数要好。您可以在末尾添加一个键,并将值设置为计数。【参考方案5】:

您可以使用penlight library。这有一个函数size,它给出了表格的实际大小。

它实现了许多我们在 Lua 中编程时可能需要和缺少的功能。

这是使用它的示例。

> tablex = require "pl.tablex"
> a = 
> a[2] = 2
> a[3] = 3 
> a['blah'] = 24

> #a
0

> tablex.size(a)
3

【讨论】:

是的,但所做的只是for k in pairs(t) do i = i + 1 end,所以它并不比这个主题上的其他选项更好,并且增加了使用另一个库的额外开销【参考方案6】:
function GetTableLng(tbl)
  local getN = 0
  for n in pairs(tbl) do 
    getN = getN + 1 
  end
  return getN
end

你是对的。没有其他方法可以获取表格长度

【讨论】:

【参考方案7】:
local function CountedTable(x)
    assert(type(x) == 'table', 'bad parameter #1: must be table')

    local new_t = 
    local mt = 

    -- `all` will represent the number of both
    local all = 0
    for k, v in pairs(x) do
        all = all + 1
    end

    mt.__newindex = function(t, k, v)
        if v == nil then
            if rawget(x, k) ~= nil then
                all = all - 1
            end
        else
            if rawget(x, k) == nil then
                all = all + 1
            end
        end

        rawset(x, k, v)
    end

    mt.__index = function(t, k)
        if k == 'totalCount' then return all
        else return rawget(x, k) end
    end

    return setmetatable(new_t, mt)
end

local bar = CountedTable  x = 23, y = 43, z = 334, [true] = true 

assert(bar.totalCount == 4)
assert(bar.x == 23)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = 24
bar.x = 25
assert(bar.x == 25)
assert(bar.totalCount == 4)

【讨论】:

__newindex 仅在定义新键时调用,因此当我们将nil 设置为存在键时,没有机会调用__newindex【参考方案8】:

似乎当通过insert方法添加表格的元素时,getn会正确返回。否则,我们必须计算所有元素

mytable = 
element1 = version = 1.1
element2 = version = 1.2
table.insert(mytable, element1)
table.insert(mytable, element2)
print(table.getn(mytable))

它会正确打印 2

【讨论】:

【参考方案9】:

我偶然发现了这个线程并想发布另一个选项。我正在使用从块控制器生成的 Luad,但它本质上是通过检查表中的值,然后将要检查的值增加 1 来工作的。最终,表将用完,并且该索引处的值将为零。

所以从返回 nil 的索引中减去 1,这就是表的大小。

我有一个 TableSize 的全局变量,它设置为这个计数的结果。

function Check_Table_Size()
  local Count = 1
  local CurrentVal = (CueNames[tonumber(Count)])
  local repeating = true
  print(Count)
  while repeating == true do
    if CurrentVal ~= nil then
      Count = Count + 1
      CurrentVal = CueNames[tonumber(Count)]
     else
      repeating = false
      TableSize = Count - 1
    end
  end
  print(TableSize)
end

【讨论】:

以上是关于如何获取 Lua 表中的条目数?的主要内容,如果未能解决你的问题,请参考以下文章

如何从Lua中的表中获取值?

如何在 Lua 中获取表的最新 x 条目?

如何获取测量中的条目数

Lua如何从表中获取数据

如何使用 LINQ 从表中获取最新条目?

Alamofire - 如何获取表中的记录数