确定 Lua 表是不是为空(不包含条目)的最有效方法?

Posted

技术标签:

【中文标题】确定 Lua 表是不是为空(不包含条目)的最有效方法?【英文标题】:Most efficient way to determine if a Lua table is empty (contains no entries)?确定 Lua 表是否为空(不包含条目)的最有效方法? 【发布时间】:2010-11-18 03:52:37 【问题描述】:

确定表是否为空(即当前既不包含数组样式值也不包含字典样式值)的最有效方法是什么?

目前,我正在使用next()

if not next(myTable) then
    -- Table is empty
end

有没有更有效的方法?

注意:# 运算符在这里不够用,因为它只对表中的数组样式值进行操作 - 因此#test=2# 无法区分,因为两者都返回 0。还请注意,检查是否表变量 nil 不够,因为我不是在寻找 nil 值,而是在寻找具有 0 个条目的表(即 )。

【问题讨论】:

【参考方案1】:

您的代码高效但错误。 (考虑[false]=0。)正确的代码是

if next(myTable) == nil then
   -- myTable is empty
end

为了获得最大效率,您需要将 next 绑定到局部变量,例如,

...
local next = next 
...
... if next(...) ...

(当next 是本地的时,代码通过恒定时间索引操作找到原始函数next 到“upvalues”数组中。当next 保持全局时,查找next 涉及索引索引“环境”哈希表,其中包含全局变量的值。此索引操作仍然是常数时间,但它比查找局部变量的数组要慢得多。)

【讨论】:

技术正确性的好点;在特定情况下,我一直在使用原始代码,false 不是预期的密钥,因此if not 工作正常,但我可能会养成与nil 比较的习惯,而不是将来,就像一个好习惯一样。是的,我一直在将常用的实用程序函数绑定到本地变量以提高速度。感谢您的意见。 当代码按预期工作时,我很难同意错误 为什么我们通过 local next 来提高速度? @Moberg 这是由于 LUA 处理其命名空间的方式。非常愚蠢的版本,它会首先爬上本地表,所以如果当前块中有local next,它将使用它,然后爬到下一个块,并重复。一旦脱离本地,它只会使用全局命名空间。这是它的一个简化版,但归根结底,它绝对意味着程序速度方面的差异。 @Moberg 在运行时全局变量需要哈希表查找,但 local 变量只需要数组查找。【参考方案2】:

如果重载,最好避免评估 __eq。

if rawequal(next(myTable), nil) then
   -- myTable is empty
end

if type(next(myTable)) == "nil" then
   -- myTable is empty
end

【讨论】:

我是一个 Lua 菜鸟,试图理解为什么这个答案被否决了。我猜这是因为在 Lua 中,“如果两个对象有不同的元方法,则相等操作会导致错误,甚至没有调用任何元方法”。 (引用在this page from Programming in Lua on lua.org 的底部)。这是否消除了避免 __eq 为 nil 重载的需要?【参考方案3】:

一种可能性是通过使用元表“newindex”键来计算元素的数量。当分配不是nil 的东西时,递增计数器(计数器也可以存在于元表中),当分配nil 时,递减计数器。

测试空表是用 0 测试计数器。

这是指向metatable documentation的指针

我确实喜欢你的解决方案,老实说,我不能假设我的解决方案总体上更快。

【讨论】:

最初的问题不是只计算“数组”条目。 0x6 的建议并非特定于数组样式的条目(newindex 适用于数字和非数字索引)。但是,主要问题是检测何时分配nil,因为如果表中已存在键,__newindex 不会触发。 要使这个技巧起作用,元表必须同时实现__index__newindex,将实际数据存储在影子表中并保持真实表为空,这样__index 将是完全调用。大声思考,我怀疑每次查找所增加的成本都不值得。【参考方案4】:

这可能是你想要的:

function table.empty (self)
    for _, _ in pairs(self) do
        return false
    end
    return true
end

a =  
print(table.empty(a))
a["hi"] = 2
print(table.empty(a))
a["hi"] = nil
print(table.empty(a))

输出:

true
false
true

【讨论】:

next() 比循环遍历pairs() 更高效(也更简洁)。 事实上,循环遍历pairs()本质上只是使用next()技术,但开销更大。 另外,不推荐写入标准的table库。【参考方案5】:

试试蛇,为我工作

serpent = require 'serpent'

function vtext(value)
  return serpent.block(value, comment=false)
end

myTable = 

if type(myTable) == 'table' and vtext(myTable) == '' then
   -- myTable is empty
end

【讨论】:

【参考方案6】:

我知道这是旧的,我可能会以某种方式误解你,但你只是希望桌子是空的,也就是说,除非你只是检查它是否是并且你实际上并不想要或不需要它是空的,你可以通过简单地重新创建它来清除它,除非我弄错了。这可以通过以下语法来完成。

yourtablename =  -- this seems to work for me when I need to clear a table.

【讨论】:

这不是问题。【参考方案7】:

这个怎么样?

if endmyTable[1] == nil then
  -- myTable is empty
end

【讨论】:

这不适用于作为索引字符串的表 或索引1 处没有值的表。考虑[2] = true【参考方案8】:

尝试使用#。它返回表中的所有实例。如果表中没有实例,则返回0

if #myTable==0 then
print('There is no instance in this table')
end

【讨论】:

提问者说# 在这里不够用,并给出了原因;你能解释一下为什么会绕过这些原因吗? 嗯...我不知道。我是新手,所以我知道的唯一方法是使用# # 仅适用于从索引 1 开始的连续数组。以下表格无效:a=true[2]=true

以上是关于确定 Lua 表是不是为空(不包含条目)的最有效方法?的主要内容,如果未能解决你的问题,请参考以下文章

使用位深度来确定 BMP 图像中颜色表的大小是不是有效?

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

如何检查Lua中的值是不是为空?

如何通过键删除 lua 表条目?

确定 MySQL 中的列值是不是为空/非空

试图比较 Lua 中一张表的所有条目