按所包含值的长度对哈希进行排序

说我有一个哈希:

foo = { :bar => ['r', 'baz'], # has a total str length of 4 characters inside of the array :baz => ['words', 'etc', 'long words'] # has a total str length of 18 characters inside of the array, :blah => ['at'] # has a total str length of 2 characters inside of the array # etc... } 

我将如何按照数组中包含的项的总字符串长度对此哈希进行排序? 在这种情况下生成的哈希顺序应为:blah, :bar, :baz

我只是这样做:

 Hash[foo.sort_by { |k, v| v.join.length }] 

我假设您不打算更改原始哈希值,只需重新排序。

传统上,散列不是有序的,因此不可排序。 Ruby 1.9哈希是有序的,但该语言没有提供重新排序元素的简单方法。 就像在1.8中一样,对哈希进行排序会返回一对数组:

 { c:3, a:1, b:2 }.sort => [ [:a,1], [:b,2], [:c,3] ] 

(实际上,1.8会对此产生影响,因为符号在1.8中没有可比性,但没关系。)

但只要您对配对列表没问题,就可以按照您喜欢的任何方式对哈希(或数组)进行排序。 只需使用sort_by并传递一个提取排序键的块,或者使用sort进行比较:

 foo.sort_by { |key, strings| strings.join.length } 

或者,如果你想要最长的那个:

 foo.sort_by { |key, strings| -strings.join.length } 

然后,如果你使用的是1.9并希望将结果变回Hash,那么你可以这样做(感谢JörgWMittag):

 Hash[ foo.sort_by { |key, strings| strings.join.length } ] 

…这与d11wtq的答案相同。

哈希不保证其概念中键的顺序。 但是在Ruby 1.9中, Hash的关键顺序被保存了 。 因此,如果使用1.9,则可以在其他答案中使用代码。

但我不想建议依赖这种行为,因为它是隐含的行为,我害怕未来的变化。 相反,使用方法以字符串长度的总和的顺序产生散列条目。

 def each_by_length(hash) hash = hash.sort_by { |_, strs| strs.map(&:length).inject(0, &:+) } hash.each do |k, v| yield k, v end end 
  foo.sort_by { |_,v| v.reduce(:+).size }