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


120

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

目前,我正在使用next()

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

有没有更有效的方法?

注意:#此处的运算符不足,因为它仅对表中的数组样式值进行运算-因此与之没有#{test=2}区别,#{}因为两者都返回0。另外请注意,检查表变量是否nil不足,因为我不是在寻找nil个值,而是具有0个条目的表(即{})。

Answers:


151

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

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

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

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

1
关于技术正确性的要点;在某些情况下,我一直在使用原始代码,false这不是预期的密钥,因此可以正常if not工作,但是将来我可能会养成一个习惯,即与之进行比较nil。是的,我一直在将通用实用程序功能绑定到本地var以提高速度。感谢您的输入。
琥珀色的

1
当代码按预期工作时,我很难同意错误
RD Alkire

4
为什么我们通过这样做来提高速度local next
Moberg

2
@Moberg这是由于LUA如何处理其名称空间。非常笨拙的版本是,它将首先爬上本地表,因此如果local next当前块中有一个,它将使用该表,然后爬到下一个块,然后重复。一旦离开本地,它将仅使用全局命名空间。这是它的精简版,但是最后,它绝对意味着程序速度上的差异。
ATaco

在lua 5.2和5.3的上下文中,@ Moberg的版本比较简单,因为非本地变量是upval或_ENV查找。更新必须经过额外的间接层,而_ENV查找是表查找。而局部是在VM寄存器
异议Rumed

1

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

测试空表将测试计数器为0。

这是指向元文档的指针

我确实喜欢您的解决方案,但老实说,我不能认为我的解决方案总体上更快。


5
最初的问题不只是计算“数组”项。
lhf

3
0x6的建议并不特定于数组样式的条目(newindex适用于数字索引和非数字索引)。但是,主要问题将是检测何时nil分配时间,因为如果表中已经存在键,则__newindex不会触发。
琥珀色

3
为了使此技巧起作用,元表必须同时实现__index__newindex,将实际数据存储在影子表中,并使实际表为空,以便__index将其完全调用。大声考虑,我怀疑每次查找的增加成本都不值得。
RBerteig

0

这可能是您想要的:

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

11
next()比循环遍历更有效(更简洁)pairs()
2012年

8
事实上,遍历pairs() 基本上只是使用next()技术,但更多的开销。
dubiousjim 2012年

7
另外,table不建议写入标准库。
Ti Strga 2014年

-1

如果过载,最好避免对__eq的求值。

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

要么

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

1
我是一个Lua新手,试图理解为什么这个答案被否决。我猜是因为在Lua中,“如果两个对象具有不同的元方法,则相等运算将导致false,甚至不调用任何元方法”。(引言位于lua.org上Lua编程的页面底部)。这是否消除了避免__eq重载为nil的需要?
SansWit

-1

试蛇,为我工作

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


-3

我知道这很老了,我可能会以某种方式误解您,但是您只是希望表为空,也就是说,除非您只是检查表是否为空,并且实际上并不需要或不需要它为空,您可以通过简单地重新创建它来清除它,除非我弄错了。可以使用以下语法完成此操作。

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

4
那不是问题。
于昊

-6

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

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

1
询问者说,这#在这里还不够,并给出了原因。您能解释一下为什么会绕开这些原因吗?
ameed

好吧...我不知道。我是新来的,所以我知道的唯一方法是使用#
arthurgps2
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.