1
votes

I am trying to group_by month/year, and category then sum all the values. Can anyone help? My code below, does group by month/year, but does not seem to sum the category values.

Setup

This is an example for data used in the group by code

require 'time'          
require "active_support"

Expense = Struct.new(:event_date, :category, :value)

    Data = [ 
             Expense.new("03/1/2000", "Auto", 10), 
             Expense.new("05/1/2000", "Rent", 10), 
             Expense.new("06/1/2000", "Food", 10), 
             Expense.new("025/1/2000", "Food", 10),

             Expense.new("02/02/2000", "Auto", 20),        
             Expense.new("03/02/2000", "Rent", 20),        
             Expense.new("04/2/2000", "Food", 20),         
             Expense.new("11/2/2000", "Food", 20),         
             Expense.new("20/2/2000", "Office Supply", 20),
             Expense.new("24/2/2000", "Office Supply", 42),

             Expense.new("01/03/2000", "Auto", 30),         
             Expense.new("03/3/2000", "Rent", 30),          
             Expense.new("04/3/2000", "Food", 30),          
             Expense.new("24/03/2000", "Food", 30),         
             Expense.new("22/3/2000", "Office Supply", 30), 
             Expense.new("12/03/2000", "Office Supply", 63),

             Expense.new("05/5/2000", "Auto", 50),          
             Expense.new("06/5/2000", "Rent", 50),          
             Expense.new("07/05/2000", "Food", 50),         
             Expense.new("11/05/2000", "Food", 50),         
             Expense.new("13/05/2000", "Office Supply", 50),
             Expense.new("16/05/2000", "Office Supply", 105)
         ]                                                  

Group by code

It groups by month and year, then groups all the categories and is suppose to sum the values for each category.

gdata = Data.group_by { |t| DateTime.parse(t.event_date).strftime("%B/%Y") }.each do |k,v|
  v.group_by{|i| i.category }.each do |k,v|                                               
    vs= v.inject(0){ |sum, i| sum + i.value.to_i }                                        
  end                                                                                     
end                                                                                       

OUTPUT

This is the output, you can see that there are several of the same categories for the same date. There should only be one value record for each category for each month/year.

   gdata.each{|i| puts i}  # => 

{
"January/2000"=>
[#<struct Expense event_date="03/1/2000", category="Auto", value=10>, 
#<struct Expense event_date="05/1/2000", category="Rent", value=10>, 
#<struct Expense event_date="06/1/2000", category="Food", value=10>, 
#<struct Expense event_date="025/1/2000", category="Food", value=10>],

 "February/2000"=>[
#<struct Expense event_date="02/02/2000", category="Auto", value=20>, 
#<struct Expense event_date="03/02/2000", category="Rent", value=20>, 
#<struct Expense event_date="04/2/2000", category="Food", value=20>, 
#<struct Expense event_date="11/2/2000", category="Food", value=20>, 
#<struct Expense event_date="20/2/2000", category="Office Supply", value=20>, 
#<struct Expense event_date="24/2/2000", category="Office Supply", value=42>], 

"March/2000"=>[
#<struct Expense event_date="01/03/2000", category="Auto", value=30>, 
#<struct Expense event_date="03/3/2000", category="Rent", value=30>, 
#<struct Expense event_date="04/3/2000", category="Food", value=30>, 
#<struct Expense eve...
1

1 Answers

1
votes

I think your biggest problem is that you're using .each, where you're simply iterating, instead of .map where you could return something different for every element of your iteration.
Something like this should work for you:

gdata = Data.group_by { |t| DateTime.parse(t.event_date).strftime('%B/%Y') }
            .map do |date, values|
  { date => values.group_by(&:category).map do |cat, expenses|
    {
      category: cat,
      sum: expenses.sum(&:value),
      expenses: expenses
    }
  end }
end