按散列数组分组

时间:2018-11-05 23:05:12

标签: ruby

对于散列数组:

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

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

4 个答案:

答案 0 :(得分:3)

这是通常会完成的一种方式。

 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(也称为merge!)的形式,该形式采用一个块来确定合并的两个哈希中存在的键的值。 有关三个块变量_on的定义,请参阅doc。其中第一个拥有通用密钥。对于块计算中未使用的块变量,通常使用_

请注意,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}}

答案 1 :(得分:2)

您可以分组和映射:

array
  .group_by { |el| [el[:id], el[:name]] }
  .map { |k,v| v.first.merge(count: v.length) }

答案 2 :(得分:2)

略有不同,如果任何元素的count属性大于1,则作为奖励会产生预期的结果。

> array.group_by { |e| [e[:id], e[:name]] }.values
    .map { |group| group.first.merge(count: group.sum { |e| e[:count] }) }
#> [{:id=>1, :name=>"name", :count=>2}, {:id=>1, :name=>"new name", :count=>1}]

> array = [{:id=>1, :name=>"name", :count=>2}, 
           {:id=>1, :name=>"name", :count=>3}, 
           {:id=>1, :name=>"new name", :count=>1}]
> array.group_by { |e| [e[:id], e[:name]] }.values
    .map { |group| group.first.merge(count: group.sum { |e| e[:count] }) }
#> [{:id=>1, :name=>"name", :count=>5}, {:id=>1, :name=>"new name", :count=>1}]

答案 3 :(得分:0)

另一个选项,您可以在map_with_object中初始化哈希:

array
  .group_by { |h| h[:name] }.values
  .map{ |e| e.map.with_object({name: e[0][:name], id: e[0][:id], count: 0}){ |h, nh| nh[:count] += h[:count] } }
#=> [{:name=>"name", :id=>1, :count=>3}, {:name=>"new name", :id=>1, :count=>1}]