将哈希数组减少为新哈希值

The*_*ice 2 ruby

我有一个ActiveRecord关系,看起来像这样:

[  
  {  
    timestamp: Tue, 02 Oct 2018 00:00:00 PDT -07:00,
    user_id: 3,
    organization_id: 1,
    all_sales: 10,
    direct_sales: 7,
    referred_sales: 3,
  },
  {
    timestamp: Wed, 03 Oct 2018 00:00:00 PDT -07:00,
    user_id: 3,
    organization_id: 1,
    all_sales: 17,
    direct_sales: 8,
    referred_sales: 9,
  },  
  {
    timestamp: Thu, 04 Oct 2018 00:00:00 PDT -07:00,
    user_id: 3,
    all_sales: 3,
    direct_sales: 3,
    referred_sales: 0,
  }
]
Run Code Online (Sandbox Code Playgroud)

我想做的是创建一个与销售相关的所有关键字的"总和"(为了我们的目的,我不需要timestamp,user_id或者organization_id,基本上,我想以这样的结尾:

{
  all_sales: 30
  direct_sales: 18
  referred_sales: 12
}
Run Code Online (Sandbox Code Playgroud)

有这种优雅的ruby-ish方式吗?我可以轻松地为每个销售类别创建一组变量,并在迭代原始关系时对其进行扩充,但我想看看社区是否有更清晰的方法.实际上,这些哈希中的每一个都有超过3个相关键,因此我担心这种方法会很快变得混乱.

编辑:我也在SO上检查了类似问题的其他一些答案(例如:更好地在散列数组中对值进行求和),但理想情况下我不会迭代这么多次.

Mar*_*iej 5

这将起作用:

arr.each_with_object({}) do |obj, hash|
  %i[all_sales direct_sales referred_sales].each do |sym|
    hash[sym] = hash[sym].to_i + obj[sym]
  end
end
Run Code Online (Sandbox Code Playgroud)

这是一次迭代,您可以将嵌套循环编写为 3 行不同的行,但在我看来,这种方式更简洁一些。

注意:to_i在获取先前值的同时调用hash[sym]它最初是niland nil.to_i == 0。或者,您可以将所有未知计数初始化为 0,如下所示:

arr.each_with_object(Hash.new(0)) do |obj, hash|
  %i[all_sales direct_sales referred_sales].each do |sym|
    hash[sym] += obj[sym]
  end
end
Run Code Online (Sandbox Code Playgroud)


cod*_*mev 5

由于您是从ActiveRecord Relation开始的,因此您可以使用pluck来计算SQL的所有总和,并让它返回一个包含总数的数组:

SalesModel.pluck('SUM(all_sales)', 'SUM(direct_sales)', 'SUM(referred_sales)')
#=> [30, 18, 12]
Run Code Online (Sandbox Code Playgroud)