按值的顺序迭代 table
Iterate over table in order of value
假设我有一个 table 像这样:
{
value = 4
},
{
value = 3
},
{
value = 1
},
{
value = 2
}
我想遍历它并按顺序打印值,所以输出如下:
1
2
3
4
我该怎么做,我知道如何使用 ipairs
和 pairs
,以及 table.sort
,但这只有在使用 table.insert 时才有效,关键是有效,我需要按值的顺序遍历它。
我尝试了一个自定义函数,但它只是以错误的顺序打印它们。
我试过:
- 创建索引并循环
- 正在对 table 进行排序(抛出错误:尝试在 table 和 table 上执行 __lt)
- 排序、索引和其他 table 的组合不仅不起作用,而且使它变得非常复杂。
我真的很难过。
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
克隆到一个新的sorted
table,然后对已排序的table进行排序。然后它将 sorted
table 移交给 ipairs()
,并且 ipairs
输出要由 for
循环使用的迭代器。
使用:
for i,v in sortByValue( myTable ) do
print(v)
end
虽然这可以确保您的原始 table 保持不变,但它的缺点是每次您进行迭代时,迭代器都必须克隆 myTable
以创建新的 sorted
table,然后table.sort
即sorted
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.
假设我有一个 table 像这样:
{
value = 4
},
{
value = 3
},
{
value = 1
},
{
value = 2
}
我想遍历它并按顺序打印值,所以输出如下:
1
2
3
4
我该怎么做,我知道如何使用 ipairs
和 pairs
,以及 table.sort
,但这只有在使用 table.insert 时才有效,关键是有效,我需要按值的顺序遍历它。
我尝试了一个自定义函数,但它只是以错误的顺序打印它们。
我试过:
- 创建索引并循环
- 正在对 table 进行排序(抛出错误:尝试在 table 和 table 上执行 __lt)
- 排序、索引和其他 table 的组合不仅不起作用,而且使它变得非常复杂。
我真的很难过。
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
克隆到一个新的sorted
table,然后对已排序的table进行排序。然后它将 sorted
table 移交给 ipairs()
,并且 ipairs
输出要由 for
循环使用的迭代器。
使用:
for i,v in sortByValue( myTable ) do
print(v)
end
虽然这可以确保您的原始 table 保持不变,但它的缺点是每次您进行迭代时,迭代器都必须克隆 myTable
以创建新的 sorted
table,然后table.sort
即sorted
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.