1

假设我有一张这样的桌子:

{
   value = 4
},
{
   value = 3
},
{
   value = 1
},
{
   value = 2
}

我想对此进行迭代并按顺序打印该值,因此输出如下所示:

1
2
3
4

我该怎么做,我了解如何使用ipairsand pairs, and table.sort,但这仅在使用 table.insert 并且密钥有效时才有效,我需要按值的顺序循环。

我尝试了一个自定义函数,但它只是以错误的顺序打印它们。

我努力了:

  • 创建索引并循环
  • 对表进行排序(抛出错误:尝试对表和表执行 __lt)
  • 排序、索引和其他表的组合不仅不起作用,而且还变得非常复杂。

我很好,真的很难过。

4

2 回答 2

2

对表格进行排序

这是正确的解决方案。

(抛出错误:尝试对表和表执行 __lt)

听起来您尝试使用a < b.

为了让 Lua 能够对值进行排序,它必须知道如何比较它们。它知道如何比较数字和字符串,但默认情况下它知道如何比较两个表。考虑一下:

local people = {
    { name = 'fred', age = 43 },
    { name = 'ted', age = 31 },
    { name = 'ned', age = 12 },
}

如果我叫人sort,Lua怎么会知道我的意图?我不知道“年龄”或“姓名”是什么意思,或者我想用哪个来比较。我必须告诉它。

可以将元表添加表中,它告诉 Lua<运算符对表的含义,但您也可以提供sort一个回调函数,告诉它如何比较两个对象。

您提供sort一个接收两个值的函数,并使用您对表格的了解返回第一个值是否“小于”第二个值。对于您的表格:

table.sort(t, function(a,b) return a.value < b.value end)

for i,entry in ipairs(t) do
    print(i,entry.value)
end
于 2015-08-11T15:27:10.813 回答
0

如果您想保持原始表不变,您可以创建一个自定义的“按值排序”迭代器,如下所示:

local function valueSort(a,b)
    return a.value < b.value;
end

function sortByValue( tbl ) -- use as iterator
    -- build new table to sort
    local sorted = {};
    for i,v in ipairs( tbl ) do sorted[i] = v end;
    -- sort new table
    table.sort( sorted, valueSort );
    -- return iterator
    return ipairs( sorted );
end

sortByValue()被调用时,它会克隆tbl到一个新sorted表,然后对已排序的表进行排序。然后它将sorted表交给ipairs(),并输出循环ipairs使用的迭代器。for

要使用:

for i,v in sortByValue( myTable ) do
  print(v)
end

虽然这可以确保您的原始表保持不变,但它的缺点是每次进行迭代时,迭代器都必须克隆myTable以创建一个新sorted表,然后table.sort是该sorted表。

sortByValue()如果性能至关重要,您可以通过“缓存”迭代器完成的工作来大大加快速度。更新代码:

local resort, sorted = true;

local function valueSort(a,b)
    return a.value < b.value;
end

function sortByValue( tbl ) -- use as iterator
    if not sorted then -- rebuild sorted table
        sorted = {};
        for i,v in ipairs( tbl ) do sorted[i] = v end;
        resort = true;
    end
    if resort then -- sort the 'sorted' table
        table.sort( sorted, valueSort );
        resort = false;
    end
    -- return iterator
    return ipairs( sorted );
end

每次在myTableset中添加或删除元素时sorted = nil。这让迭代器知道它需要重建sorted表(并重新排序)。

每次更新value嵌套表之一中的属性时,设置resort = true. 这让迭代器知道它必须执行一个table.sort.

现在,当您使用迭代器时,它将尝试并重新使用缓存sorted表中先前排序的结果。

如果它找不到sorted表(例如,在第一次使用迭代器时,或者因为您设置sorted = nil强制重建),它将重建它。如果它认为它需要求助(例如,在第一次使用时,或者如果sorted表被重建,或者如果你设置resort = true了),那么它将使用sorted表。

于 2015-08-23T14:38:05.663 回答