Reputation: 25348
I have a date range that I'm using to query a database with. The returned result is an array of hashes like so:
[
{:created=>"2013-12-10", :amount=>1},
{:created=>"2014-02-20", :amount=>1},
{:created=>"2014-02-23", :amount=>4},
{:created=>"2014-02-24", :amount=>1},
{:created=>"2014-03-06", :amount=>1},
{:created=>"2014-03-14", :amount=>3},
{:created=>"2014-03-15", :amount=>1},
{:created=>"2014-03-17", :amount=>1},
{:created=>"2014-03-20", :amount=>1},
{:created=>"2014-03-21", :amount=>1},
{:created=>"2014-03-24", :amount=>1},
{:created=>"2014-03-25", :amount=>1},
{:created=>"2014-03-28", :amount=>1},
{:created=>"2014-04-05", :amount=>1},
{:created=>"2014-04-07", :amount=>1}
]
What I need to do is group and sum the amount
by month, and in the case where a month has no data but is part of the initial range, show 0
.
So in my example above, the date range I queried the database with was 2013-11-13
to 2014-04-18
.
Output is ultimately just a basic array of the data grouped month and summed. So the example above should produce:
[0, 1, 0, 6, 11, 2]
Those array items coordinate to: November, December, January, February, March, April.
FWIW, I'm running Ruby 2.0.0 and this is part of a Rails 4 app, if there happen to be some special Rails helper methods that would be useful here.
Upvotes: 0
Views: 1061
Reputation: 16507
You can use #group_by
methods to group by year, and month, and then combination of #map
, #uniq
, and #reduce
to get proper Array
:
# grouping record by year and month, and then sorting them
g = a.group_by {|v| Date.parse(v[:created][0,7] + '-01') }.sort
# generating a result hash
h = Hash[g]
# generating range
range = Date.new(2013,11)..Date.new(2014,04)
# here we firstly remap to get *year-month* list by dates, which will contain only
# one date per month, then we calculate sum for each month value.
range.to_a.map {|d| Date.new(d.year,d.month,1)}.uniq.map {|d| h[d] && h[d].reduce(0) {|sum,h| sum + h[:amount]} || 0 }
# => [0, 1, 0, 6, 11, 2]
for rails you can use #try
method:
range.to_a.map {|d| Date.new(d.year,d.month,1)}.uniq.map {|d| h[d].try(:reduce, 0) {|sum,h| sum + h[:amount]} || 0 }
Upvotes: 1