简体   繁体   中英

how do I merge array of hashes summing by the value?

I have an array of hashes

[{:id=>1, :book=>{:title=>"title1", :desc=>"title1", :author=>"title1"}, :pages=>10},
 {:id=>1, :book=>{:title=>"title1", :desc=>"title1", :author=>"title1"}, :pages=>10},
 {:id=>2, :book=>{:title=>"title2", :desc=>"title2", :author=>"title2"}, :pages=>30}]

How do I sum pages value leaving only unique keys? Eg.:

[{:id=>1, :book=>{:title=>"title1", :desc=>"title1", :author=>"title1"}, :pages=>20},
 {:id=>2, :book=>{:title=>"title2", :desc=>"title2", :author=>"title2"}, :pages=>30}]

Let's group by id and map each result to a structure where the pages are the sum of all the pages for that id

array.
  group_by { |item| item[:id] }.
  map do |id, items| 
    page_sum = items.sum { |i| i[:pages] }
    Hash[:id, id, :book, items.first[:book], :pages, page_sum] 
  end
arr = [
  {:id=>1, :book=>{:title=>"title1", :desc=>"title1", :author=>"title1"}, :pages=>10},
  {:id=>1, :book=>{:title=>"title1", :desc=>"title1", :author=>"title1"}, :pages=>10},
  {:id=>2, :book=>{:title=>"title2", :desc=>"title2", :author=>"title2"}, :pages=>30}
]

arr.each_with_object({}) do |g,h|
  h.update(g[:id]=>g) { |_,o,n| o.merge(pages: o[:pages] + n[:pages]) }
end.values
  #=> [{:id=>1, :book=>{:title=>"title1", :desc=>"title1", :author=>"title1"}, :pages=>30},
  #    {:id=>2, :book=>{:title=>"title2", :desc=>"title2", :author=>"title2"}, :pages=>30}] 

Note the receiver of values equals

{1=>{:id=>1, :book=>{:title=>"title1", :desc=>"title1", :author=>"title1"}, :pages=>30},
 2=>{:id=>2, :book=>{:title=>"title2", :desc=>"title2", :author=>"title2"}, :pages=>30}} 

This uses the form of Hash#update (aka merge! ) that employs the block

{ |_,o,n| o.merge(pages: o[:pages] + n[:pages]) }

to determine the values of keys (the block variable _ ) that are present in both hashes being merged. See the doc for an explanation of the block variables o and n .

Hash#update and Enumerable#group_by are the two methods one generally reaches for when dealing with problems of this kind. Either can be used. They are roughly equal in efficiency, so the choice is largely one of personal preference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM