【问题标题】:How to iterate over an ActiveRecord resultset in one line with nil check in Ruby如何在 Ruby 中使用 nil 检查在一行中迭代 ActiveRecord 结果集
【发布时间】:2021-01-12 21:56:24
【问题描述】:

我有一个 Active Record 结果数组,我想遍历每条记录以获取特定属性,并将它们全部添加到一行中并进行 nil 检查。这是我到目前为止得到的结果

def total_cost(cost_rec)
    total= 0.0
    unless cost_rec.nil?
      cost_rec.each { |c| total += c.cost }
    end
    total
  end

有没有一种优雅的方法可以在一行中做同样的事情?

【问题讨论】:

  • 如果您尝试对列中的值求和,我建议您尝试直接从数据库中获取总和,而不是遍历所有对象。它应该性能更高(在速度和资源方面)
  • 目前我必须在数据库之外进行求和,但同意你的看法,如果可以在数据库内完成会更好

标签: ruby-on-rails ruby one-liner


【解决方案1】:

您可以结合安全导航(“隐藏”nil 检查)、数据库内的求和(以避免从数据库中提取一堆您不需要的数据)和#to_f调用隐藏最后的nil检查:

cost_rec&.sum(:cost).to_f

如果cost是一个整数,那么:

cost_rec&.sum(:cost).to_i

如果cost 是数据库中的numeric,并且您不想担心精度问题:

cost_rec&.sum(:cost).to_d

如果cost_rec 是一个数组而不是一个关系(即您已经从数据库中提取了所有数据),那么其中之一:

cost_rec&.sum(&:cost).to_f
cost_rec&.sum(&:cost).to_i
cost_rec&.sum(&:cost).to_d

取决于cost 是什么类型。

您也可以使用Kernel#Array 来忽略nils(因为Array(nil)[])并忽略数组和ActiveRecord 关系之间的差异(因为#Array 调用#to_ary 并且关系对此作出响应)并说:

Array(cost_rec).sum(&:cost)

这甚至允许cost_rec 成为单个模型实例。这也绕过了对最终#to_X 调用的需要,因为[].sum0。这种方法的缺点是当cost_rec 是一个关系时,您无法将总和推送到数据库中。

【讨论】:

  • 我喜欢你的 oneliner,但有时我只会有一个记录,而 sum 给了我一个错误。处理这种情况还有其他选择吗?
  • @soLegacy 在这种情况下你可以说Array(cost_rec).sum(&:cost)。不需要&. nil 检查,因为Array(nil)[][].sum 是零,所以你不需要尾随to_X 调用。
  • @soLegacy #Array 方法更加灵活,正如我在更新的答案中所指出的那样。
【解决方案2】:

有什么类似的吗?

def total_cost(cost_rec)
  (cost_rec || []).inject(0) { |memo, c| memo + c.cost }
end

def total_cost(cost_rec)
  (cost_rec || []).sum(&:cost)
end

【讨论】:

  • 还有Array(cost_rec).sum(&:cost) 允许cost_rec 成为单个模型实例、nil、模型数组或ActiveRecord 关系。
【解决方案3】:

其中任何一个都应该工作

total = cost_rec.map(&:cost).compact.sum
total = cost_rec.map{|c| c.cost }.compact.sum
total = cost_rec.pluck(:cost).compact.sum

编辑:如果 cost_rec 为 nil

total = (cost_rec || []).map{|c| c.cost }.compact.sum

【讨论】:

  • 如果 cost_rec 为 nil,我认为你有问题
【解决方案4】:

cost_recActiveRecord::Relatation 时,这应该是开箱即用的:

cost_rec.sum(:cost)

ActiveRecord::Calculations#sum

【讨论】:

    猜你喜欢
    • 2013-08-05
    • 2016-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-20
    相关资源
    最近更新 更多