2

I have the following hash and I would like to group by year/month and sum the values:

range = {
"2020-11-06 00:00:00 +0000" => 234100.14176395803,
"2020-11-07 00:00:00 +0000" => 57731.63072153537,
"2020-11-08 00:00:00 +0000" => 68903.8902730576,
"2020-11-09 00:00:00 +0000" => 180971.98008691627,
........
"2021-02-01 00:00:00 +0000" => 169004.96299567595,
"2021-02-02 00:00:00 +0000" => 183363.9687217272,
"2021-02-03 00:00:00 +0000" => 200400.2505103338
}

I was able to do the group: hash = Hash[range.collect { |k,v| [k.to_date.strftime("%Y-%m"), v]}] but I'm unable to get the values sum, the value results and getting with the hash collect is only the last day.

{
"2020-11" => 155346.83103528828,
"2020-12" => 175424.41029800082,
"2021-01" => 55366.44438577791,
"2021-02" => 200400.2505103338
}

Using reduce method hash.values.reduce(:+) I can get the total values but I need them by year by month.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Jose Perez
  • 35
  • 5

2 Answers2

1

You could build a new hash via each_with_object:

range.each_with_object(Hash.new(0)) { |(k, v), h| h[k[0, 7]] += v }
#=> {"2020-11"=>541707.6428454672, ..., "2021-02"=>552769.1822277369}

Instead of k[0, 7] you can also use k.to_date.strftime('%Y-%m')

Stefan
  • 109,145
  • 14
  • 143
  • 218
1

First we need to group it into months. This can be done easiest using .group_by.

hash = Hash[range.group_by { |k,_v| k.to_date.strftime("%Y-%m")}]

Using the same code you already provided, just group_by instead of collect.

{
  "2020-11"=>[
    ["2020-11-06 00:00:00 +0000", 234100.14176395803],
    ["2020-11-07 00:00:00 +0000", 57731.63072153537],
    ["2020-11-08 00:00:00 +0000", 68903.8902730576],
    ["2020-11-09 00:00:00 +0000", 180971.98008691627]
  ],
  "2021-02"=>[
    ["2021-02-01 00:00:00 +0000", 169004.96299567595],
    ["2021-02-02 00:00:00 +0000", 183363.9687217272],
    ["2021-02-03 00:00:00 +0000", 200400.2505103338]
  ]
}

Now we need to sum (equivalent to reduce(:+) you tried with a few benefits) them together. We need to modify each value of the hash and sum the last element of each element in the value.

hash.transform_values {|a| a.sum(&:last) }

returns

{
  "2020-11" => 541707.6428454673,
  "2021-02" => 552769.1822277369
}
Siim Liiser
  • 3,860
  • 11
  • 13