如何按 "score" 然后 "index" 对 Lua 中的内部表进行排序?

How to sort inner tables in Lua by their "score" and then "index"?

我将以下 Lua table 存储在变量 T 中:

{
    ["mn"] = { ["index"] = 7, ["key"] = "mn", ["score"] = 0 },
    ["kl"] = { ["index"] = 6, ["key"] = "kl", ["score"] = .4 },
    ["ef"] = { ["index"] = 3, ["key"] = "ef", ["score"] = .3 },
    ["ab"] = { ["index"] = 1, ["key"] = "ab", ["score"] = 0 },
    ["cd"] = { ["index"] = 2, ["key"] = "cd", ["score"] = .1 },
    ["gh"] = { ["index"] = 4, ["key"] = "gh", ["score"] = 0 },
    ["ij"] = { ["index"] = 5, ["key"] = "ij", ["score"] = .2 }
}

我想按以下方式对 T table 的所有内部 table 进行排序:
1. score高的表放在最前面
2. score 相等的表按 index 排序。

因此,排序后,输出应产生以下顺序 table:

{
    [1] = { ["index"] = 6, ["key"] = "kl", ["score"] = .4 }, -- highest "score"
    [2] = { ["index"] = 3, ["key"] = "ef", ["score"] = .3 },
    [3] = { ["index"] = 5, ["key"] = "ij", ["score"] = .2 },
    [4] = { ["index"] = 2, ["key"] = "cd", ["score"] = .1 },
    [5] = { ["index"] = 1, ["key"] = "ab", ["score"] = 0 }, -- lowest "score", lowest "index"
    [6] = { ["index"] = 4, ["key"] = "gh", ["score"] = 0 }, -- when scores are the same, sort by their "index" instead
    [7] = { ["index"] = 7, ["key"] = "mn", ["score"] = 0 } -- lowest "score", highest "index"
}

如何实现这个Luatable排序?

在lua中,table包含两种数据结构:数组和字典。

排序是指对数组进行排序,其中每个元素都与一个数字索引相关联,并且索引是连续的,即:1,2,3...

你的初始 table 实际上是一个字典 - 每个条目都有一个与之关联的任意键(在你的情况下,它们是字符串)。

因此,您描述的实际上不是排序任务,您最终想要一种不同的table。

table.sort 适用于 lua table 的数组部分,即索引从 1 开始到第一个 nil 条目结束的那些元素。

a={s=3,['r']=3,  5,3,2,  nil,21}
                 |these|
                 |ones |

因此,您首先创建一个数组并对其进行排序:

local sorted={}
for k,v in pairs(T) do
  table.insert(sorted,v)
end
table.sort(sorted,function(a,b)
  --your code here
  --function should return true if element `a`  from the array `sorted`
  --must be higher (to the left of) `b`
end)

或者,您可以将条目存储在字典和数组部分的相同 table 中,table.sort 函数将忽略字典。但是使用 pairs 遍历 table 并同时添加新元素是不明智的。因此,惯用的方式仍然会涉及中间副本。

您需要先将您拥有的哈希值转换为 table,然后使用按 score(降序)排序的自定义排序函数对 table 的元素进行排序) 然后 index (升序)对于那些具有相同分数的元素。

像这样的东西应该可以工作:

local hash = {
    ["mn"] = { ["index"] = 7, ["key"] = "mn", ["score"] = 0 },
    ["kl"] = { ["index"] = 6, ["key"] = "kl", ["score"] = .4 },
    ["ef"] = { ["index"] = 3, ["key"] = "ef", ["score"] = .3 },
    ["ab"] = { ["index"] = 1, ["key"] = "ab", ["score"] = 0 },
    ["cd"] = { ["index"] = 2, ["key"] = "cd", ["score"] = .1 },
    ["gh"] = { ["index"] = 4, ["key"] = "gh", ["score"] = 0 },
    ["ij"] = { ["index"] = 5, ["key"] = "ij", ["score"] = .2 }
}
local tbl = {}
for _,v in pairs(hash) do
  table.insert(tbl, v)
end
table.sort(tbl, function(a,b)
    return a.score > b.score or a.score == b.score and a.index < b.index
  end)