Lua - 排序 table 并随机化关系
Lua - Sort table and randomize ties
我有一个 table 有两个值,一个是 name (字符串和唯一),另一个是数字值(在本例中 hearts).我想要的是:按 hearts 对 table 进行排序,但是当有平局时随机打乱项目(例如 hearts 是相等的).通过标准的排序功能,在平局的情况下,顺序总是相同的,每次排序功能工作时我都需要不同的顺序。
这是一个例子:
tbl = {{name = "a", hearts = 5}, {name = "b", hearts = 2}, {name = "c", hearts = 6}, {name = "d", hearts = 2}, {name = "e", hearts = 2}, {name = "f", hearts = 7}}
sort1 = function (a, b) return a.hearts > b.hearts end
sort2 = function (a, b)
if a.hearts ~= b.hearts then return a.hearts > b.hearts
else return a.name > b.name end
end
table.sort(tbl, sort2)
local s = ""
for i = 1, #tbl do
s = s .. tbl[i].name .. "(" .. tbl[i].hearts .. ") "
end
print(s)
现在,有了函数 sort2
,我想我完全明白了。问题是,当 a.hearts == b.hearts
时会发生什么?在我的代码中,它只是按领带的名字来排序,而不是我想要的。我有两个想法:
- 首先随机打乱table中的所有项目,然后应用
sort1
。
- 给table的每一个元素加一个值,叫做
rnd
,就是一个随机数。然后在 sort2
中,当 a.hearts == b.hearts
按 a.rnd > b.rnd
订购商品时。
- 在
sort2
中,当a.hearts == b.hearts
随机生成true或false时,return它。它不起作用,我知道发生这种情况是因为随机 true/false 使订单功能崩溃,因为可能存在不一致。
我不喜欢 1(因为我想在排序函数中执行所有操作)和 2(因为它需要添加一个值),我想执行类似 3 但可以工作的操作。问题是:有没有办法以简单的方式做到这一点,这样做的最佳方式是什么? (也许,方法 1 或 2 是最优的,但我不明白)。
奖金问题。此外,我需要修复一个项目并对其他项目进行排序。例如,假设我们希望 "c"
排在第一位。做一个单独的table,只有要排序的项目,排序table,然后添加固定项目好吗?
-- example table
local tbl = {
{ name = "a", hearts = 5 },
{ name = "b", hearts = 2 },
{ name = "c", hearts = 6 },
{ name = "d", hearts = 2 },
{ name = "e", hearts = 2 },
{ name = "f", hearts = 7 },
}
-- avoid same results on subsequent requests
math.randomseed( os.time() )
---
-- Randomly sort a table
--
-- @param tbl Table to be sorted
-- @param corrections Table with your corrections
--
function rnd_sort( tbl, corrections )
local rnd = corrections or {}
table.sort( tbl,
function ( a, b)
rnd[a.name] = rnd[a.name] or math.random()
rnd[b.name] = rnd[b.name] or math.random()
return a.hearts + rnd[a.name] > b.hearts + rnd[b.name]
end )
end
---
-- Show the values of our table for debug purposes
--
function show( tbl )
local s = ""
for i = 1, #tbl do
s = s .. tbl[i].name .. "(" .. tbl[i].hearts .. ") "
end
print(s)
end
for i = 1, 10 do
rnd_sort(tbl)
show(tbl)
end
rnd_sort( tbl, {c=1000000} ) -- now "c" will be the first
show(tbl)
如果您有空引入新的依赖项,您可以使用 lazylualinq 为您完成这项工作(或者检查它如何排序序列,如果您不需要其余部分):
local from = require("linq")
math.randomseed(os.time())
tbl = {{name = "a", hearts = 5}, {name = "b", hearts = 2}, {name = "c", hearts = 6}, {name = "d", hearts = 2}, {name = "e", hearts = 2}, {name = "f", hearts = 7}}
from(tbl)
:orderBy("x => x.hearts")
:thenBy("x => math.random(-1, 1)")
:foreach(function(_, x) print(x.name, x.hearts) end)
这是一个快速打乱(打乱)数字索引表的函数:
function shuffle(tbl) -- suffles numeric indices
local len, random = #tbl, math.random ;
for i = len, 2, -1 do
local j = random( 1, i );
tbl[i], tbl[j] = tbl[j], tbl[i];
end
return tbl;
end
我有一个 table 有两个值,一个是 name (字符串和唯一),另一个是数字值(在本例中 hearts).我想要的是:按 hearts 对 table 进行排序,但是当有平局时随机打乱项目(例如 hearts 是相等的).通过标准的排序功能,在平局的情况下,顺序总是相同的,每次排序功能工作时我都需要不同的顺序。 这是一个例子:
tbl = {{name = "a", hearts = 5}, {name = "b", hearts = 2}, {name = "c", hearts = 6}, {name = "d", hearts = 2}, {name = "e", hearts = 2}, {name = "f", hearts = 7}}
sort1 = function (a, b) return a.hearts > b.hearts end
sort2 = function (a, b)
if a.hearts ~= b.hearts then return a.hearts > b.hearts
else return a.name > b.name end
end
table.sort(tbl, sort2)
local s = ""
for i = 1, #tbl do
s = s .. tbl[i].name .. "(" .. tbl[i].hearts .. ") "
end
print(s)
现在,有了函数 sort2
,我想我完全明白了。问题是,当 a.hearts == b.hearts
时会发生什么?在我的代码中,它只是按领带的名字来排序,而不是我想要的。我有两个想法:
- 首先随机打乱table中的所有项目,然后应用
sort1
。 - 给table的每一个元素加一个值,叫做
rnd
,就是一个随机数。然后在sort2
中,当a.hearts == b.hearts
按a.rnd > b.rnd
订购商品时。 - 在
sort2
中,当a.hearts == b.hearts
随机生成true或false时,return它。它不起作用,我知道发生这种情况是因为随机 true/false 使订单功能崩溃,因为可能存在不一致。
我不喜欢 1(因为我想在排序函数中执行所有操作)和 2(因为它需要添加一个值),我想执行类似 3 但可以工作的操作。问题是:有没有办法以简单的方式做到这一点,这样做的最佳方式是什么? (也许,方法 1 或 2 是最优的,但我不明白)。
奖金问题。此外,我需要修复一个项目并对其他项目进行排序。例如,假设我们希望 "c"
排在第一位。做一个单独的table,只有要排序的项目,排序table,然后添加固定项目好吗?
-- example table
local tbl = {
{ name = "a", hearts = 5 },
{ name = "b", hearts = 2 },
{ name = "c", hearts = 6 },
{ name = "d", hearts = 2 },
{ name = "e", hearts = 2 },
{ name = "f", hearts = 7 },
}
-- avoid same results on subsequent requests
math.randomseed( os.time() )
---
-- Randomly sort a table
--
-- @param tbl Table to be sorted
-- @param corrections Table with your corrections
--
function rnd_sort( tbl, corrections )
local rnd = corrections or {}
table.sort( tbl,
function ( a, b)
rnd[a.name] = rnd[a.name] or math.random()
rnd[b.name] = rnd[b.name] or math.random()
return a.hearts + rnd[a.name] > b.hearts + rnd[b.name]
end )
end
---
-- Show the values of our table for debug purposes
--
function show( tbl )
local s = ""
for i = 1, #tbl do
s = s .. tbl[i].name .. "(" .. tbl[i].hearts .. ") "
end
print(s)
end
for i = 1, 10 do
rnd_sort(tbl)
show(tbl)
end
rnd_sort( tbl, {c=1000000} ) -- now "c" will be the first
show(tbl)
如果您有空引入新的依赖项,您可以使用 lazylualinq 为您完成这项工作(或者检查它如何排序序列,如果您不需要其余部分):
local from = require("linq")
math.randomseed(os.time())
tbl = {{name = "a", hearts = 5}, {name = "b", hearts = 2}, {name = "c", hearts = 6}, {name = "d", hearts = 2}, {name = "e", hearts = 2}, {name = "f", hearts = 7}}
from(tbl)
:orderBy("x => x.hearts")
:thenBy("x => math.random(-1, 1)")
:foreach(function(_, x) print(x.name, x.hearts) end)
这是一个快速打乱(打乱)数字索引表的函数:
function shuffle(tbl) -- suffles numeric indices
local len, random = #tbl, math.random ;
for i = len, 2, -1 do
local j = random( 1, i );
tbl[i], tbl[j] = tbl[j], tbl[i];
end
return tbl;
end