简体   繁体   English

Lua - 排序表并随机化关系

[英]Lua - Sort table and randomize ties

I have a table with two values, one is a name (string and unique) and the other is a number value (in this case hearts ).我有一个包含两个值的表,一个是名称(字符串和唯一值),另一个是数值(在本例中为heart )。 What I want is this: sort the table by hearts but scramble randomly the items when there is a tie (eg hearts is equal).我想要的是:按红心对桌子进行排序,但在平局时随机打乱项目(例如红心相等)。 By a standard sorting function, in case of ties the order is always the same and I need it to be different every time the sorting function works.通过标准的排序功能,在平局的情况下,顺序总是相同的,每次排序功能工作时我都需要它不同。 This is anexample:这是一个例子:

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)

Now, with the function sort2 I think I quite got the problem.现在,使用sort2函数,我想我完全有问题。 The problem is, what happens when a.hearts == b.hearts ?问题是,当a.hearts == b.hearts时会发生什么? In my code it just orders the ties by their name, not what I want.在我的代码中,它只是按名称排序关系,而不是我想要的。 I have two ideas:我有两个想法:

  1. First scramble randomly all the items in the table, then apply sort1 .首先随机打乱表中的所有项目,然后应用sort1
  2. Add a value to every element of the table, called rnd , that is a random number.向表的每个元素添加一个值,称为rnd ,这是一个随机数。 Then in sort2 , when a.hearts == b.hearts order the items by a.rnd > b.rnd .然后在sort2 ,当a.hearts == b.heartsa.rnd > b.rnd对项目进行a.rnd > b.rnd
  3. In sort2 , when a.hearts == b.hearts generate randomly true or false and return it.sort2 ,当a.hearts == b.hearts随机生成 true 或 false 并返回它。 It doesn't work, and I understand that this happens because the random true/false makes the order function crash since there could be inconsistencies.它不起作用,我知道发生这种情况是因为随机真/假使订单函数崩溃,因为可能存在不一致。

I don't like 1 (because I would like to do everything inside the sorting function) and 2 (since it requires to add a value), I would like to do something like 3 but working.我不喜欢 1(因为我想在排序函数中做所有事情)和 2(因为它需要添加一个值),我想做类似 3 的事情但可以工作。 The question is: is there a way do to this in a simple manner, and what is an optimal way of doing this?问题是:有没有办法以简单的方式做到这一点,这样做的最佳方法是什么? (maybe, method 1 or 2 are optimal and I don't get it). (也许,方法 1 或 2 是最佳的,我不明白)。

Bonus question.奖金问题。 Moreover, I need to fix an item and sort the others.此外,我需要修复一个项目并对其他项目进行排序。 For example, suppose we want "c" to be first.例如,假设我们希望"c"在第一位。 Is it good to make a separate table with only the items to sort, sort the table and then add the fixed items?制作一个单独的表格,只有要排序的项目,对表格进行排序然后添加固定项目是否好?

-- 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)

Here's a quick function for shuffling (scrambling) numerically indexed tables:这是一个用于打乱(打乱)数字索引表的快速函数:

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

If you are free to introduce a new dependency, you can use lazylualinq to do the job for you (or check out how it sorts sequences, if you do not need the rest):如果您可以随意引入新的依赖项,则可以使用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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM