简体   繁体   中英

With Ruby, how do I combine an array of hashes to sum totals by date?

I have an array of arrays, each containing the number of orders by a given week. How do I merge this together to give a sum total for each week?

[
  [
    {:week_beginning=>Mon, 13 Feb 2017, :orders_total=>"1.00"}, 
    {:week_beginning=>Mon, 20 Feb 2017, :orders_total=>"3.00"}
  ], 
  [
    {:week_beginning=>Mon, 13 Feb 2017, :orders_total=>"2.00"}, 
    {:week_beginning=>Mon, 20 Feb 2017, :orders_total=>"7.00"}
  ], 
  [
    {:week_beginning=>Mon, 13 Feb 2017, :orders_total=>"3.00"},  
    {:week_beginning=>Mon, 20 Feb 2017, :orders_total=>"3.00"}
  ]
]

So that I end up with..?

[
  {:week_beginning=>Mon, 13 Feb 2017, :orders_total=>"6.00"}, 
  {:week_beginning=>Mon, 20 Feb 2017, :orders_total=>"13.00"}
]

Letting arr be your array, you can do the following using Enumerable#group_by .

arr.flatten.group_by { |g| g[:week_beginning] }.
    map { |k,v| { week_beginning: k, orders_total: v.sum { |g|
      g[:orders_total].to_f }.to_s } }
 #=> [{:week_beginning=>"Mon, 13 Feb 2017", :orders_total=>"6.0"},
 #    {:week_beginning=>"Mon, 20 Feb 2017", :orders_total=>"13.0"}]

Note that

arr.flatten.group_by { |g| g[:week_beginning] }
  #=> {"Mon, 13 Feb 2017"=> [
  #      {:week_beginning=>"Mon, 13 Feb 2017", :orders_total=>"1.00"},
  #      {:week_beginning=>"Mon, 13 Feb 2017", :orders_total=>"2.00"},
  #      {:week_beginning=>"Mon, 13 Feb 2017", :orders_total=>"3.00"}
  #    ],
  #    "Mon, 20 Feb 2017"=>[
  #      {:week_beginning=>"Mon, 20 Feb 2017", :orders_total=>"3.00"},
  #      {:week_beginning=>"Mon, 20 Feb 2017", :orders_total=>"7.00"},
  #      {:week_beginning=>"Mon, 20 Feb 2017", :orders_total=>"3.00"}
  #    ]
  #   }

Alternatively, you could use a counting hash (see the version of Hash::new where new takes an argument called the default value ).

arr.flatten.each_with_object(Hash.new(0)) do |g,h|
  h.update(g[:week_beginning]=>g[:orders_total].to_f) { |_,o,n| o + n }
end.map { |k,v| {week_beginning: k, orders_total: v.to_s } }
  #=> [{:week_beginning=>"Mon, 13 Feb 2017", :orders_total=>"6.0"},
  #    {:week_beginning=>"Mon, 20 Feb 2017", :orders_total=>"13.0"}]

map 's receiver is the following.

arr.flatten.each_with_object(Hash.new(0)) do |g,h|
  h.update(g[:week_beginning]=>g[:orders_total].to_f) { |_,o,n| o + n }
end
  #=> {"Mon, 13 Feb 2017"=>6.0, "Mon, 20 Feb 2017"=>13.0}

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