【问题标题】:How to sum elements of an array?如何对数组的元素求和?
【发布时间】:2014-12-15 08:22:57
【问题描述】:

我的问题是两个折叠。首先,我有一个未规范化的表,其中包含 3 对数据(6 列),它们必须相加。大致是这样的:

|-module_a-|-value_a-|-module_b-|-value_b-|-module_c-|-value_c-|
----------------------------------------------------------------
|   02     |    15   |    nil   |   nil   |   nil    |   nil   |
|   01     |    10   |    00    |   10    |   nil    |   nil   |
|   00     |    25   |    nil   |   nil   |   nil    |   nil   |
|   02     |    22   |    01    |   15    |   03     |   20    |
|   03     |    10   |    nil   |   nil   |   nil    |   nil   |
|   02     |     8   |    00    |   5     |   nil    |   nil   |

我的主要目标是获得每个模块的总和,但是由于它们可以混合在 3 个字段中,因此通过 activerecord 来完成它变得很复杂(或者我认为)。

无论如何,为了清理它,我制作了一个这样的数组:

tok1=Office.select('module_a as module, value_a as value')
tok2=Office.select('module_b as module, value_b as value').where.not(:value_b => nil)
tok3=Office.select('module_c as module, value_c as value').where.not(:value_c => nil)

tok=(tok1+tok2+tok3)

结果:

|-module-|-value-|
------------------
|   02   |  15   |
|   01   |  10   |
|   00   |  25   |
|   02   |  22   |
|   03   |  10   |
|   02   |   8   |
|   00   |  10   |
|   01   |  15   |
|   03   |  20   |
|   00   |   5   |

到目前为止,一切都很好。

现在,我想对模块值求和。如果我可以通过 ActiveRecord 进行 GROUP 和 SUM,这将非常简单,但结果变量 tok 是一个数组,因此不可能有 ActiveRecord 函数。如果我尝试通过tok=tok1.merge(tok2) 合并它们,我最终只会得到 tok2 的结果,我认为这是因为我在查询 Office 表时重命名了这些字段,我不确定。我尝试以不同的方式将它们组合在一起,但我得到一个错误,即关系不是不可变的。

无论如何,由于执行tok=tok1+tok2+tok3 的结果以数组结尾,我想通过将其视为数组来求和。我尝试过使用map,在使用tok.map{|h| [h.module, h.value]} 之后,我最终得到了一个这样的数组:

{[02, 15], [01, 10], [00,  25}, [02, 22], [03,10], [02, 8], [00,10], [01,15], [03,20], [00, 5]}

我不知道如何从这里开始。我试着把它变成一个哈希,但我对 map 方法还是太陌生,所以我不知道该怎么做。理想情况下,我认为应该是这样的:

{ ["02" => 15],["01" => 10],["00" => 25],["02" => 22],["03" => 10],["02" => 8],
  ["00" => 10],["01" => 15],["03" => 20],["00" => 5]}

我在其他问题中读过如何用这样的哈希/数组对值求和,所以如果我像这样得到它,我想我会被设置。

抱歉,解释混乱。

【问题讨论】:

  • module 是 Ruby 中的保留字,因此请注意如何使用它。尝试访问名为 module 的属性(例如在上面的 SELECT 子句中使用的属性)时,您可能会得到意外的结果或错误。
  • 这只是一个例子。我实际上没有具有该名称的字段。

标签: ruby-on-rails ruby ruby-on-rails-4


【解决方案1】:

数据库通常非常擅长分组和添加东西,所以我可能会尽可能多地在 SQL 中做这件事。

tok = Office.find_by_sql <<-END_SQL
  SELECT module, SUM(value)
  FROM (
    SELECT module_a AS module, value_a AS value FROM offices
    UNION
    SELECT module_b AS module, value_b AS value FROM offices WHERE value_b IS NOT NULL
    UNION
    SELECT module_c AS module, value_c AS value FROM offices WHERE value_c IS NOT NULL
  ) AS modules(module, value)
  GROUP BY module
END_SQL

评估为具有以下属性的Office 实例的集合:

+--------+-------+
| module | value |
+--------+-------+
| 1      | 25    |
| 3      | 30    |
| 0      | 40    |
| 2      | 45    |
+--------+-------+

如果由我决定,我可能会使用给定的 SQL 查询创建一个视图,并在其上添加一个 ActiveRecord 数据模型。这样Office 模型就不会用于最初预期之外的目的。由于 DBMS 和分支之间的实现视图与原始主题相去甚远,因此这里不再赘述。

【讨论】:

    【解决方案2】:

    你可以这样做:

    arr = [[02, 15], [01, 10], [00,  25], [02, 22], [03,10], [02, 8], [00,10], [01,15], [03,20], [00, 5]]
    hash = {}
    arr.each do |item|
      hash[item[0]] ||= 0
      hash[item[0]] += item[1]
    end
    hash # => {2=>45, 1=>25, 0=>40, 3=>30}
    

    或者没有以前的地图:

    hash = {}
    tok.each do |item|
      hash[item.module] ||= 0
      hash[item.module] += item.value
    end
    

    编辑:正如 Dima Goltsman 在评论中提到的(谢谢!)它可以使用注入以更短的形式重写:

    arr = [[02, 15], [01, 10], [00,  25], [02, 22], [03,10], [02, 8], [00,10], [01,15], [03,20], [00, 5]]    
    arr.inject(Hash.new(0)) do |hash, item|
      hash[item[0]] += item[1]
      hash
    end # => {2=>45, 1=>25, 0=>40, 3=>30}
    

    tok.inject(Hash.new(0)) do |hash, item|
      hash[item.module] += item.value
      hash
    end
    

    【讨论】:

    • 有趣。你能解释一下hash[item[0]] ||= 0在做什么吗?
    • 它实际上是一个快捷方式:hash[item[0]] || hash[item[0]] = 0。因此,如果 hash[item[0]] 已经存在 - 什么都不会发生。如果它是 nil(或 false)——它将被初始化为 0。它是最常见的 Ruby 习惯用法之一——你可以在这里找到很多关于它的信息stackoverflow.com/questions/613985/common-ruby-idioms
    • 最好使用inject 方法,它是您所做工作的捷径
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-04
    相关资源
    最近更新 更多