如何按数字值对Ruby哈希进行排序?

184
我有一个计数哈希表,我想要按照计数值进行排序。我遇到的问题是默认的Hash.sort函数将数字作为字符串进行排序而非根据数字大小进行排序。
例如,给定哈希表:
metrics = {"sitea.com" => 745, "siteb.com" => 9, "sitec.com" => 10 }

运行以下代码:

metrics.sort {|a1,a2| a2[1]<=>a1[1]}

将返回一个已排序的数组:

[ 'siteb.com', 9, 'sitea.com', 745, 'sitec.com', 10]

尽管745是比9大的数字,但9将首先出现在列表中。当试图展示谁拥有最高计数时,这使我的生活变得困难 :)

有什么想法可以按数字值大小对哈希(或数组甚至)进行排序吗?

感激任何帮助。


你使用的 Ruby 版本是什么?你的排序结果非常奇怪。 - fl00r
4个回答

314

我不知道您如何获得您的结果,因为按字符串值排序无法实现... 您应该在示例中反转a1a2

无论如何,最佳方法是(根据Mladen):

metrics = {"sitea.com" => 745, "siteb.com" => 9, "sitec.com" => 10 }
metrics.sort_by {|_key, value| value}
  # ==> [["siteb.com", 9], ["sitec.com", 10], ["sitea.com", 745]]

如果你需要一个哈希作为结果,你可以使用to_h(在Ruby 2.0+中)

metrics.sort_by {|_key, value| value}.to_h
  # ==> {"siteb.com" => 9, "sitec.com" => 10, "sitea.com", 745}

91
可以简单地使用 sort_by{|k,v| v} 进行排序。 - Mladen Jablanović
21
@Elchin:您可以使用metrics.sort_by{ |k, v| v }.reverse.to_h。这段代码会按值对字典进行排序并返回一个新的有序字典,其中键值对按值从大到小排列。 - Marc-André Lafortune
@Marc-André Lafortune,完全是我的错,没有看见 #to_h!谢谢! - Elchin
4
更简单的写法是:hash.sort_by(&:last),需要注意的是这个方法会返回一个由键值对组成的数组,而不是 Hash。 - Gerry Gleason
2
你可以使用 metrics.sort_by{|k,v| -v} 进行反向排序。 - bragboy
显示剩余13条评论

103

由于值是最后一个输入,因此您可以执行以下操作:

metrics.sort_by(&:last)

5
太棒了! &:last 的预定义参考在哪里可以找到? - Tamer Shlash
3
sort_by(&:last) 实际上是 sort_by {|x| x.last} 的简写形式。https://dev59.com/vHM_5IYBdhLWcg3wzmrL - Beni Cherniavsky-Paskin

15

已经有答案,但还是需要更改你的代码:

metrics.sort {|a1,a2| a2[1].to_i <=> a1[1].to_i }

无论是否转换为字符串,这段代码都可以完成任务。


10

这不是我所看到的行为:

irb(main):001:0> metrics = {"sitea.com" => 745, "siteb.com" => 9, "sitec.com" =>
 10 }
=> {"siteb.com"=>9, "sitec.com"=>10, "sitea.com"=>745}
irb(main):002:0> metrics.sort {|a1,a2| a2[1]<=>a1[1]}
=> [["sitea.com", 745], ["sitec.com", 10], ["siteb.com", 9]]

您的数字是否可能在某个地方被转换为字符串?您是否有未发布的更多代码?


啊,你说得对,看起来我的代码返回的结果是字符串。数据类型有时候真是让人头疼。 :) 有时候我可能太过于接近问题了。谢谢。 - Dustin M.
2
是的。偶尔我会听到有人把 Ruby 称为“无类型语言”。哦,不,它肯定是有类型的。只是它不是静态类型的。 :) - Jacob Mattison

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接