对于散列数组:
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
是否有更优雅的方法来达到预期效果?
答案 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!
)的形式,该形式采用一个块来确定合并的两个哈希中存在的键的值。
有关三个块变量_
,o
和n
的定义,请参阅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}]