我有一个 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
有没有一种优雅的方法可以在一行中做同样的事情?
我有一个 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
有没有一种优雅的方法可以在一行中做同样的事情?
像这些吗?
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
这些中的任何一个都应该工作
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 为零
total = (cost_rec || []).map{|c| c.cost }.compact.sum
您可以结合安全导航(“隐藏”nil
检查)、数据库内的求和(以避免从数据库中提取一堆不需要的数据)以及隐藏最终检查的#to_f
调用:nil
cost_rec&.sum(:cost).to_f
如果cost
是整数,则:
cost_rec&.sum(:cost).to_i
并且 ifcost
是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
忽略nil
s (因为Array(nil)
is []
)并忽略数组和 ActiveRecord 关系之间的区别(因为#Array
调用#to_ary
和关系对此作出响应)并说:
Array(cost_rec).sum(&:cost)
这甚至允许cost_rec
成为单个模型实例。这也绕过了对最终#to_X
调用的需要,因为[].sum
is 0
。这种方法的缺点是您不能在cost_rec
关系中将总和推送到数据库中。
什么时候cost_rec
是ActiveRecord::Relatation
然后这应该开箱即用:
cost_rec.sum(:cost)