首页 > 解决方案 > 按哈希数组分组

问题描述

对于哈希数组:

array = [{id: 1, name: 'name', count: 2},
         {id: 1, name: 'name', count: 1},
         {id: 1, name: 'new name', count: 1}]

我想要结果:

[{id: 1, name: 'name', count: 3},
 {id: 1, name: 'new name', count: 1}]

我通过以下方式实现了这一目标:

grouped_data = array.each_with_object(Hash.new(0)) do |row, sum|
  sum["#{row.fetch(:id)} #{row.fetch(:name)}"] += row.fetch(:count).to_i
end

result = array.uniq.each do |row|
  row[:count] = grouped_data["#{row.fetch(:id)} #{row.fetch(:name)}"]
  row
end

有没有更优雅的方法来达到预期的效果?

标签: ruby

解决方案


这是通常会做的一种方式。

 array.each_with_object({}) {|g,h| h.update(g[:name]=>g) {|_,o,n|
   o.merge(count: o[:count] + n[:count]) } }.values
  #=> [{:id=>1, :name=>"name", :count=>1},
  #    {:id=>1, :name=>"new name", :count=>1}]

这使用Hash#update (aka merge!) 的形式,它使用一个块来确定在被合并的两个散列中存在的键的值。有关三个块变量和的定义_,请参见文档。其中第一个持有通用密钥。通常的做法是用于块计算中未使用的块变量。on_

注意的接收者values如下。

array.each_with_object({}) {|g,h| h.update(g[:name]=>g) {|_,o,n|
  o.merge(count: o[:count] + n[:count]) } }
  #=> {"name"=>{:id=>1, :name=>"name", :count=>2},
  #    "new name"=>{:id=>1, :name=>"new name", :count=>1}}

推荐阅读