按值的顺序迭代 table

Iterate over table in order of value

假设我有一个 table 像这样:

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

我想遍历它并按顺序打印值,所以输出如下:

1
2
3
4

我该怎么做,我知道如何使用 ipairspairs,以及 table.sort,但这只有在使用 table.insert 时才有效,关键是有效,我需要按值的顺序遍历它。

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

我试过:

我真的很难过。

Sorting the table

这是正确的解决方案。

(throws error: attempt to perform __lt on table and table)

听起来您尝试使用 a < b

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

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

如果我给别人打电话sort,Lua怎么知道我的意图?我不知道 'age' 或 'name' 是什么意思,或者我想用哪个来进行比较。我必须告诉它。

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

您向 sort 提供了一个接收两个值的函数,并且您 return 是否第一个是 "less than" 第二个,使用您对 table 的了解。对于您的 tables:

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

for i,entry in ipairs(t) do
    print(i,entry.value)
end

如果您想保持原来的 table 不变,您可以像这样创建一个自定义 'sort by value' 迭代器:

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克隆到一个新的sortedtable,然后对已排序的table进行排序。然后它将 sorted table 移交给 ipairs(),并且 ipairs 输出要由 for 循环使用的迭代器。

使用:

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

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

如果性能至关重要,您可以通过 'caching' 由 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

每次添加或删除元素时 to/from myTable 设置 sorted = nil。这让迭代器知道它需要重建 sorted table(并重新排序)。

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

现在,当您使用迭代器时,它会尝试重新使用缓存 sorted table.

中的先前排序结果

如果它找不到 sorted table(例如,在第一次使用迭代器时,或者因为你设置了 sorted = nil 来强制重建)它会重建它.如果它发现它需要诉诸(例如,在第一次使用时,或者如果 sorted table 被重建,或者如果你设置 resort = true)那么它将诉诸 sorted table.