【问题标题】:Lua - Sort table and randomize tiesLua - 排序表和随机化关系
【发布时间】:2015-11-11 05:49:19
【问题描述】:

我有一个包含两个值的表,一个是 name(字符串和唯一),另一个是数字值(在本例中为 hearts)。我想要的是:按 hearts 对表格进行排序,但在出现平局时随机打乱项目(例如 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 时会发生什么?在我的代码中,它只是按他们的名字来排序,而不是我想要的。我有两个想法:

  1. 先随机打乱表中所有项目,然后申请sort1
  2. 为表格的每个元素添加一个值,称为rnd,这是一个随机数。然后在sort2,当a.hearts == b.heartsa.rnd > b.rnd订购商品。
  3. sort2中,当a.hearts == b.hearts随机生成真假并返回。它不起作用,我理解这是因为随机的真/假会导致订单函数崩溃,因为可能存在不一致。

我不喜欢 1(因为我想在排序函数中做所有事情)和 2(因为它需要添加一个值),我想做一些类似 3 的事情,但可以工作。问题是:有没有办法以简单的方式做到这一点,这样做的最佳方式是什么? (也许,方法 1 或 2 是最佳的,但我不明白)。

额外问题。此外,我需要修复一个项目并对其他项目进行排序。例如,假设我们希望 "c" 排在第一位。做一个单独的表,只有要排序的项目,排序表,然后添加固定的项目是不是很好?

【问题讨论】:

    标签: sorting random lua lua-table


    【解决方案1】:
    -- 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)
    

    【讨论】:

    • 太棒了!正是我所要求的,一个非常出色但简单的解决方案。需要注意的是,此排序功能仅在 hearts 为整数时才有效。
    • 我建议添加一些内联 cmets 来描述背后的逻辑
    • @ValerioBozz - behind logic 术语太模糊了。解决方案的哪一部分对您来说难以理解?
    • @EgorSkriptunoff 我只是建议引入更多内联 cmets :)
    • @ValerioBozz - 我的哪些代码行需要额外的内联 cmets? AFAIU self-documenting code 比包含很多内联 cmets 的代码要好。
    【解决方案2】:

    这里有一个快速洗牌(打乱)数字索引表的功能:

    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
    

    【讨论】:

      【解决方案3】:

      如果您可以随意引入新的依赖项,您可以使用 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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-07
        • 2017-09-08
        • 1970-01-01
        • 1970-01-01
        • 2013-03-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多