通过基于项的属性对对象数组进行分组来构建哈希

我想知道在ruby 1.9中是否有更规范的方法来做到这一点

我有一个包含一堆对象的数组,我想使用数组中每个对象的属性将它们分组为Hash。

简单的例子:

> sh = {} => {} > aers = %w(abcd ab bc de abc) => ["a", "b", "c", "d", "ab", "bc", "de", "abc"] > aers.each do |aer| > sh[aer.size] = [] if sh[aer.size].nil? > sh[aer.size] < end => ["a", "b", "c", "d", "ab", "bc", "de", "abc"] > sh => {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]} 

我试过这个,但它的输出是错误的(你可以看到):

  sh = Hash.new([]) => {} > aers.each do |aer| > sh[aer.size] < end => ["a", "b", "c", "d", "ab", "bc", "de", "abc"] > sh => {} 

Ruby已经预见到了你的需求,并且让你了解了Enumerable#group_by

 irb(main):001:0> aers = %w(abcd ab bc de abc) #=> ["a", "b", "c", "d", "ab", "bc", "de", "abc"] irb(main):002:0> aers.group_by{ |s| s.size } #=> {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]} 

在Ruby 1.9中,您可以通过以下方式缩短它:

 irb(main):003:0> aers.group_by(&:size) #=> {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]} 

Phrogz是正确的,group_by是有用的。 你的代码包含了ruby的一个问题。

 aers = %w(abcd ab bc de abc) sh = Hash.new([]) # returns the _same_ array everytime the key is not found. # sh = Hash.new{|h,v| h[v] = []} # This one works p sh, sh.default aers.each do |aer| sh[aer.size] << aer #modifies the default [] every time end p sh, sh.default p sh[5] 

产量

 {} [] {} ["a", "b", "c", "d", "ab", "bc", "de", "abc"] ["a", "b", "c", "d", "ab", "bc", "de", "abc"] 

你也可以通过链接方法来实现这一点……这可能只是对这个问题有学术兴趣,但仍然是一个熟悉的好技术。

 irb(main):017:0> sh = {} => {} irb(main):018:0> aers.collect{|k| k.size}.uniq!.each{|k| sh[k] = aers.select{|j| j.size == k}} => [1, 2, 3] irb(main):019:0> sh => {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]} irb(main):020:0>