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


132

听起来像是“让我为您代劳”,但不知何故我找不到答案。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"

如何不计入所有条目的数量?


3
@lhf:我编写了一个序列化器,该序列化器会记住它看到的每个对象,下次看到它时,它将发出一个整数引用而不是该对象。自然的写法是类似dictionary[value] = #dictionary + 1,其中#代表所有对象的数量。什么纳闷的是,为什么你不就希望这样的:在所有理智的用例#(见kaizer.se答案),所有对象的数量正好等于什么#已返回; 似乎让#数一切都严格来说是一种改进。当然,我是Lua新手,可能会遗漏要点。
罗曼·斯塔科夫

32
@lhf:询问程序员为什么要做所有合理的编程语言都具有简单功能的事情来质疑程序员的能力是不好的。
Timwi'4

5
@Timwi:告诉Lua语言的作者之一,Lua不在“合理的”编程语言之列,这对您很不好。;-)顺便说一句,我也从来不需要这些信息。
亚历山大·格拉迪什

5
我认为我从未使用一种语言的所有功能。这并不意味着它们对其他人无用:)
Roman Starkov

7
@sylvanaar在我看来,#运算符的定义不明确。这很容易解决:首先#确定性,然后引入新的运算符或函数以获取织补数。故事的结尾...为什么他们必须如此固执?:)
罗曼·斯塔科夫

Answers:


129

您已经有了问题的解决方案-唯一的方法是使用迭代整个表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值的连续部分的数组。


42
当我第一次意识到像lua这样的基本运算符的返回值#不是确定性的时,我仍然为自己对Lua的经历而记忆犹新。
罗曼·斯塔科夫

5
哦,可能是确定性的。这与C标准留下一些东西来实现定义的行为完全相同。之所以这样,是因为不同的实现者可以选择不同的实现选择。
赤裸裸的

19
According to the manual, any of 3, 5 and 9 are valid results for #t。根据手册,在非序列上调用#是未定义的。这意味着任何结果(-1、3、3.14、5、9)都是有效的。
cubuspl42 2014年

6
关于有效结果:u0b34a0f6ae适用于Lua 5.1,而cubuspl42适用于Lua 5.2。无论哪种情况,整个事情都是疯狂的。
杰里米(Jeremy)

9
在非序列上的#不会产生异常的事实仅仅是使使用lua有点像割伤自己感觉更好的事情之一。
2015年

21

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


是否有使用此方法处理擦除条目的便捷方法?
u0b34a0f6ae 2010年

可悲的是,除非索引不存在,否则__newindex函数似乎不会在nil赋值上触发,因此看来您必须通过特殊函数来进行条目删除。
ergosys

1
您应该将数据存储在单独的表中(例如,可以作为__index和__newindex的升值访问)。然后__index和__newindex都会为每个表访问触发。您应该检查性能是否可以接受。
亚历山大·格拉迪什

@亚历山大:是的,然后是下一个绊脚石:如果您代理该表,则按对进行的常规迭代将不起作用。我听说这将在Lua 5.2中解决。
u0b34a0f6ae 2010年

5.2中将存在__pairs和__ipairs元方法...如果要在5.1中进行操作,则必须用自己的Pairs()函数替换。但这可能太多了。:-)
亚历山大·格拉迪什

3

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

count = 0
tbl = {}

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

tbl[1] = 48
count = count + 1

print(count)   -- prints "2"

没有其他方法,#运算符将仅在具有连续键的类似数组的表上工作。



从评论中,我得到的印象是proxytable / metamethods尚未完全支持这种情况,因此,我将其视为当前可用的最佳方法。
罗曼·斯塔科夫

计数是表的唯一方法,并且在创建表时添加行比每次需要计数时都要对它们进行计数的功能要好。您可以在末尾添加键,并将值设置为计数。
亨里克·埃兰森

2

我知道获得表中条目数的最简单方法是使用“#”。只要编号,#tableName就会获得条目的数量:

tbl={
    [1]
    [2]
    [3]
    [4]
    [5]
}
print(#tbl)--prints the highest number in the table: 5

可悲的是,如果没有编号,它将无法正常工作。


2

您可以使用penlight库。它具有size提供表格实际大小的功能。

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

这是使用它的示例。

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

> #a
0

> tablex.size(a)
3

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

1
发布答案时,建议发布最少数量的直接回答问题的代码,并说明代码如何回答问题。看这里
cst1992 '16

__newindex仅在定义新键时调用,因此__newindex当我们设置nil为存在键时就没有机会调用。
Frank AK

-1

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

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

它将正确打印2

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.