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

时间:2012-06-08 23:08:27

标签: ruby

说我有一个类似的哈希:

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

4 个答案:

答案 0 :(得分:12)

我只是这样做:

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

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

答案 1 :(得分:3)

传统上,散列不是有序的,因此不可排序。 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的答案相同。

答案 2 :(得分:1)

   foo.sort_by { |_,v| v.reduce(:+).size }

答案 3 :(得分:1)

哈希不保证其概念中键的顺序。但是在Ruby 1.9中,Hash's key order is saved。因此,如果使用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