如何获取 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 表中的条目数?的主要内容,如果未能解决你的问题,请参考以下文章