Merge and sum hashes inside a Ruby array

2019-08-27 21:28发布

问题:

I have an Ruby array that looks like this:

[{ :date => '2018-02-01', :capacity => 5, :used_capacity => 3 },
 { :date => '2018-02-01', :capacity => 10, :used_capacity => 3 },
 { :date => '2018-02-02', :capacity => 5, :used_capacity => 3 }]

And I need to the hashes if they have the same date and sum the capacity and used_capacity fields.

So it needs to become:

[{ :date => '2018-02-01', :capacity => 15, :used_capacity => 6 },
 { :date => '2018-02-02', :capacity => 5, :used_capacity => 3 }]

Can anyone push me in the right direction?

Thnx!

回答1:

input = [{ :date => '2018-02-01', :capacity => 5, :used_capacity => 3 },
         { :date => '2018-02-01', :capacity => 10, :used_capacity => 3 },
         { :date => '2018-02-02', :capacity => 5, :used_capacity => 3 }]

input.group_by { |h| h[:date] }.
      values.
      map do |a|
        a.reduce do |acc, h|
          acc.merge(h) { |k, v1, v2| k == :date ? v1 : v1 + v2 }
        end
      end


回答2:

arr = [{ :date => '2018-02-01', :capacity => 5, :used_capacity => 3 },
 { :date => '2018-02-01', :capacity => 10, :used_capacity => 3 },
 { :date => '2018-02-02', :capacity => 5, :used_capacity => 3 }]

arr.each_with_object({}) do |g,h|
  h.update(g[:date]=>g) do |_,oh,nh|
    oh.merge(nh) { |k,ov,nv| k==:date ? ov : ov+nv }
  end
end.values
  #=> [{:date=>"2018-02-01", :capacity=>15, :used_capacity=>6},
  #    {:date=>"2018-02-02", :capacity=>5, :used_capacity=>3}]

This uses the forms of Hash#update (aka merge!) and Hash#merge that employ a block to determine the values of keys that are present in both hashes being merged. update.