保存最近几个月的哈希

时间:2015-06-07 02:51:07

标签: ruby-on-rails arrays ruby hash

我有一系列哈希。像这样......

transactions = [{"date"=>"2014-07-21", "amount"=>200},
               {"date"=>"2012-06-21", "amount"=>400},
               {"date"=>"2014-08-21", "amount"=>100},
               {"date"=>"2014-08-12", "amount"=>150},
               {"date"=>"2014-06-15", "amount"=>230}
               {"date"=>"2013-05-21", "amount"=>900},]

我希望能够保存每个月的总金额,然后显示最近3个月到今天的日期及其总金额。像这样......

总计:06-14 230美元           07-14 200美元           08-14 $ 250

我有这种方法,但我不知道如何只将最近3个月放入我的数据库字段以及如何将其打印出来。

def income_by_month
    @payroll_transactions = current_user.transactions
    @recent_payroll = @payroll_transactions.find_all {90.days.ago.to_date..Date.today}.map #finds transactions within 90 days
     @amount_by_month = @recent_payroll.group_by { |t| t.date.to_date.month }.map do |month, transactions|
        [month, transactions.sum(:amount)] #Groups transactions by month and adds month total
      end.to_h

- 编辑 -

我想出了一种方法,只是为了获取过去30天内的事务,我更新了我的方法以显示它。现在我的问题是如何保存答案(我将它作为数组保存在一个字段中吗?)然后如何在我的视图中显示答案。就像我在这里展示一样。如何在订单中逐行打印每个键和值?

Totals:   06-14    $230
          07-14    $200
          08-14    $250

CNC中 对不起我的数据库是一个mongoid db。我想将最近3个月保存到今天的日期,无论金额是否可用。

2 个答案:

答案 0 :(得分:1)

让我先简单介绍一下您的代码段:

group_by { |t| t.date.to_date.month }

请注意,按单month对对象进行分组不会花费一年的时间,因此它会在一个容器中结束2012年和2014年的交易金额。所以你真正想要的是根据月份和年份值进行分组。

考虑通过输入数组减少冗余迭代量(以及使用不必要的聚合),我得出了以下建议:

last_months = transactions.map{|i| Date.parse(i["date"]).strftime("%m-%Y")}.uniq.sort.last(3)
result      = last_months.inject({}){|result, input| result[input] = 0; result}
transactions.inject(result) do |result, object|
  # NOTE: we're already doing dates parsing and strftime two times here.
  # In case you operate on Date objects themselves in your code, this is not the case.
  # But the real perfomance measurement between summing all values up
  # and strftiming more than once should be done additionally.
  month = Date.parse(object["date"]).strftime("%m-%Y")
  result[month] += object["amount"] if result[month]
  result
end
# result now equals to {"06-2014"=>230, "07-2014"=>200, "08-2014"=>250}

首先,我们获得最近三个月(和几年)。 接下来,我们创建一个哈希,以包含仅包含最后几个月密钥的聚合值。最后,我们只对那些似乎是后3个月之一的交易总结amount

因此,只要ruby哈希值(ruby v.1.9 +)保留了键顺序,你可以简单地遍历它们以打印出来:

result.each{|k,v| puts "#{k}: #{v}"}
# 06-2014: 230
# 07-2014: 200
# 08-2014: 250

最后要注意的是,在服务器代码中进行这种聚合效率不高。更诱人的选择是将此计算移动到您的数据库层。

答案 1 :(得分:0)

ActiveSupport有一些漂亮的日期方法,比如Date#beginning_of_month:

require "date"
require "active_support/core_ext"

def process_transaction_group(month, transactions)
  {
    month: month.strftime("%Y/%m"),
    total: transactions.map {|t| t["amount"] }.reduce(:+)
  }
end

def process_transactions(transactions)
  transactions
    .group_by {|t| Date.parse(t["date"]).beginning_of_month }
    .select {|month, _trxs| month < 3.months.ago }
    .map {|month, trxs| process_transaction_group(month, trxs) }
end

###############

transactions = [{"date"=>"2014-07-21", "amount"=>200},
               {"date"=>"2012-06-21", "amount"=>400},
               {"date"=>"2014-08-21", "amount"=>100},
               {"date"=>"2014-08-12", "amount"=>150},
               {"date"=>"2014-06-15", "amount"=>230},
               {"date"=>"2013-05-21", "amount"=>900}]

process_transactions(transactions)
#=> [{:month=>"2014/07", :total=>200}, {:month=>"2012/06", :total=>400}, {:month=>"2014/08", :total=>250}, {:month=>"2014/06", :total=>230}, {:month=>"2013/05", :total=>900}]