我有以下哈希:
scores = {
"Charlie" => 0
"Delta" => 5
"Beta" => 2
"Alpha" => 0
}
列出的数字是整数,团队表示为字符串。
如何按分数对列表进行排序,如果存在并列,则按字母顺序列出,然后输出?
我想象的预期输出如下:
1. Delta, 5 pts
2. Beta, 2 pts
3. Alpha, 0 pts
4. Charlie, 0 pts
我对哈希进行了排序,但如果存在平局,我不确定如何按字母顺序排序。我使用的代码如下:
scores = Hash[ scores.sort_by { |team_name, scores_array| scores_array.sum.to_s } ]
答案 0 :(得分:4)
在Ruby中,Array
s are lexicographically ordered。你可以利用这个事实来按多个键进行排序:只需创建一个你想要排序的键数组:
scores.sort_by {|team, score| [-score, team] }.to_h
#=> {'Delta' => 5, 'Beta' => 2, 'Alpha' => 0, 'Charlie' => 0}
答案 1 :(得分:2)
将Hash排序为已排序的键/值对数组的一般模式如下所示。
https: // wwww.example.org/only-one-visit-per-hour-is-allowed.php
sorted_array_of_tuples = hash.sort { |a,b| ... }
有Enumerable mixin,这意味着它可以使用sort
。在哈希Hash
上使用比较键和值的元组(两个元素阵列),因此我们可以制作容易比较键和值的块。
通常您可以使用已排序的数组。
sort
但你可以使用to_h
将其变回哈希。由于Ruby中的Hashes记住了它们的键被插入的顺序,因此从已排序的Array创建的新创建的Hash将保留其排序。
sorted = hash.sort { ... }
sorted.each { |t|
puts "#{t[0]}: #{t[1]}"
}
...但是如果向sorted_hash = hash.sort { |a,b| ... }.to_h
添加了更多的密钥,它们将不会被排序,它们只会在最后进行。因此,您可能希望冻结已排序的哈希,以防止修改破坏排序。
sorted_hash
至于排序区,在其他语言中,“通过这种方式进行比较,如果它们相等,那么比较”的成语将如下所示:
sorted_hash.freeze
这有利于<=>
在相等时返回sorted_scores = scores.sort { |a,b|
# Compare values or compare keys
a[1] <=> b[1] || a[0] <=> b[0]
}
。在其他语言中,0
为0
,因此您可以使用逻辑运算符创建一系列主要,次要和第三级比较。
但在Ruby中false
不是0
。只有false
为false
。通常这是一件好事,但这意味着我们需要更加具体。
false
答案 2 :(得分:1)
您可以使用&lt; =&gt;比较并在首先按值(得分)进行比较的块中进行比较,如果匹配,则按键(名称)进行比较。
scores = {
"Alpha" => 0,
"Beta" => 2,
"Charlie" => 0,
"Delta" => 5,
}
# convert to an array of arrays
# => [[Alpha, 0], [Beta, 2], [Charlie, 0], [Delta, 5]]
# then sort by value and, if needed, by key
scores = scores.to_a.sort! { |a,b|
cmp = a[1] <=> b[1] # sort by value (index = 1)
cmp = a[0] <=> b[0] if cmp == 0 # sort by key (index = 0) if values matched
cmp
}.to_h # convert back to a hash
puts scores
或者,如果您想将比较代码提取到重用/清晰度的方法中,您可以让它调用该方法。
# Compare entries from the scores hash.
# Each entry has a name (key) and score (value) (e.g. ["Alpha", 0].
# First compare by scores, then by names (if scores match).
def compare_score_entries(a, b)
cmp = a[1] <=> b[1]
cmp = a[0] <=> b[0] if cmp == 0
return cmp
end
scores = scores.sort(&method(:compare_score_entries)).to_h
答案 3 :(得分:0)
你可以这样排序
scores = {
"Charlie" => 0,
"Delta" => 5,
"Beta" => 2,
"Alpha" => 0
}
puts scores
.map{|name, score| [-score, name]}
.sort
.zip((0...scores.size).to_a)
.map{|(score, name), i| "#{i + 1}. #{name}, #{-score} pts"}
注意减分。这是一种反向排序整数的技巧。
答案 4 :(得分:0)
你可以试试这个
scores = {
'Charlie' => 0,
'Delta' => 5,
'Beta' => 2,
'Alpha' => 0
}
scores_sorted = scores.sort_by { |_key, value| -value }
scores_sorted.each.with_index(1) do |value, index|
puts "#{index}. #{value[0]}, #{value[1]} pts"
end