如何在Ruby中对哈希进行排序

时间:2018-04-18 21:38:50

标签: ruby

我有以下哈希:

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 } ]

5 个答案:

答案 0 :(得分:4)

在Ruby中,Arrays 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] } 。在其他语言中,00,因此您可以使用逻辑运算符创建一系列主要,次要和第三级比较。

但在Ruby中false不是0。只有falsefalse。通常这是一件好事,但这意味着我们需要更加具体。

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