11

在 Lua 中,pairs可以ipairs以不同的顺序迭代相同的元素:

> t = {[1]=1, [2]=2, [3]=3}
> for k,v in pairs(t) do print(k,v) end
2       2
1       1
3       3
> for k,v in ipairs(t) do print(k,v) end
1       1
2       2
3       3

在使用 C API 时,我只看到一个用于迭代表的工具:lua_next()函数,它的作用非常类似于pairs()产生上述 2-1-3 顺序的 Lua 函数。

我正在寻找一种有效的 C 方法来按顺序迭代表的整数键(ipairs 的 C API 版本)。

我天真地认为:

int tableLength = luaL_len(L, tableIndex);
for (i=0, i++, i>tableLength){   
    // if t[i] is not null ...
}

但我不清楚表大小与连续整数键的数量不匹配的潜在性能问题:

t = {[1]=1, [2]=2, [4]=4}     -- has a (reported) length of 4
t = {[1]=1, [2]=2, [40000]=4} -- has a (reported) length of 2

如果这确实是 ipairs 的方式,那么是否有一种简单的方法可以开始使用 lua_next 和最后找到的整数键来继续遍历表的其余部分,避免再次遍历整数键部分?这样做有没有机会看到一些整数键两次?

4

2 回答 2

9

你只需使用 rawgeti 直到你得到一个 nil 键:

// Tabs is on top of stack
for ( int i=1 ; ; i++ ) {
    lua_rawgeti(L,-1,i);
    if ( lua_isnil(L,-1) ) {
        lua_pop(L,1);
        break;
    }
    /* Do something */
    lua_pop(L,1);
}

通过查看源代码,您可以看到 ipairs 在内部执行的操作:http ://www.lua.org/source/5.1/lbaselib.c.html#ipairsaux

于 2013-01-05T14:05:12.640 回答
4
t = {[1]=1, [2]=2, [4]=4}     -- has a length of 4

那么你的问题就在那里;它的长度不是 4。你可能认为它有,并且#t可能返回 4。但就 Lua API 而言,这个表的长度是undefined

Lua 5.1 状态

表 t 的长度被定义为任何整数索引 n,使得 t[n] 不为 nil 且 t[n+1] 为 nil;此外,如果t 1为零,则n可以为零。对于从 1 到给定 n 的非 nil 值的常规数组,它的长度正好是 n,它的最后一个值的索引。如果数组有“洞”(即,其他非 nil 值之间的 nil 值),那么 #t 可以是直接在 nil 值之前的任何索引(也就是说,它可以将任何这样的 nil 值视为结束的数组)。

Lua 5.2 更加明确

表 t 的长度仅在表是序列时才定义,也就是说,对于某个整数 n,其正数字键的集合等于 {1..n}。在这种情况下,n 是它的长度。请注意,像

 {10, 20, nil, 40}

不是一个序列,因为它有键 4 但没有键 3。(因此,没有 n 使得集合 {1..n} 等于该表的正数字键的集合。)但是请注意,非数字键不会影响表是否为序列。

但在这两种情况下,长度都是undefined

于 2013-01-04T00:53:36.323 回答