Ruby on rails 如何将Rails中多个对象的两个值的乘积求和?
假设我有一个投资组合Ruby on rails 如何将Rails中多个对象的两个值的乘积求和?,ruby-on-rails,ruby,ruby-on-rails-5,Ruby On Rails,Ruby,Ruby On Rails 5,假设我有一个投资组合p,它有两支股票port\u股票。我要做的是对每个港口库存进行计算,然后总结所有结果 [60] pry(main)> p.port_stocks => [#<PortStock:0x00007fd520e064e0 id: 17, portfolio_id: 1, stock_id: 385, volume: 2000, purchase_price: 5.9, total_spend: 11800.0>, #<Port
p
,它有两支股票port\u股票
。我要做的是对每个港口库存
进行计算,然后总结所有结果
[60] pry(main)> p.port_stocks
=> [#<PortStock:0x00007fd520e064e0
id: 17,
portfolio_id: 1,
stock_id: 385,
volume: 2000,
purchase_price: 5.9,
total_spend: 11800.0>,
#<PortStock:0x00007fd52045be68
id: 18,
portfolio_id: 1,
stock_id: 348,
volume: 1000,
purchase_price: 9.0,
total_spend: 9000.0>]
[61] pry(main)>
我只想得到19800
。理想情况下,我想用一种非常简单的方式来做这件事
如果我只是简单地将1total\u-spend
中的所有值相加,我知道我可以简单地做:p.port\u-stocks.map(&:total\u-spend)。sum
,就是这样
但是,当我首先对每个对象进行数学运算,然后将所有对象的所有乘积相加时,我不知道如何做类似的事情。这显然适用于2个对象或500个对象。使用Rails执行此操作的最佳方法是将一个块传递给
sum
,例如:
p.port_stocks.sum do |port_stock|
port_stock.volume * port_stock.purchase_price
end
它使用专用于对数字求和的方法,并且往往非常快速和高效——特别是与在调用无块的直接求和之前操作数据相比
快速基准测试通常显示,它的性能比明显的备选方案快约20%
我无法测试,但尝试一下,它会为您解决这个问题
让我知道你进展如何
只是一个快速更新,您还提到了最好的Ruby方式,sum
是,不过在旧版本的Ruby上您可以使用(别名为inject
):
这不如求和有效,但我想我会给你一些选择:)你可以用它来迭代所有的股票,但是要求和所有的总花费值,你可以为每只股票计算它。之后,将所有结果相加,并完成以下操作:
p.port_stocks.map{|ps| ps.volume * ps.purchase_price}.sum
或者你可以像SRack那样使用。这将通过一步/迭代返回结果。尝试:p.port_stocks.map{ps | ps.volume*ps.purchase_price}.sum
您想用Ruby还是在数据库中进行计算?与您的问题无关,但您不应该使用浮点数。@Stefan我想用Ruby进行计算。还有,我为什么要使用浮动来表示货币价值?我觉得我以前在什么地方听说过,但是你能给我一个链接或者一些我能读到更多关于这个的东西,并探索其他的选择吗?谢谢@marcamillion“为什么我应该使用浮动”-您不应该将浮动用于货币价值。因为浮点不准确,很容易引入舍入错误,例如0.1*0.2
返回0.0200000000000000004
。有关详细说明,请参阅。看看gem及其集成。后一个示例中的赋值是多余的,即只使用+
而不是+=
collection.map{…}.sum
=>collection.sum{…}
执行效果比使用sum
块差,而且可读性较低。@SRack有证据表明它的性能更差吗?我过去曾在@maramount(如果你感兴趣的话)对它进行过基准测试,在用Guitarman的解决方案回答了一个类似的问题并看到其他人发布使用sum
:)后,我很想看看映射如何,reduce
和sum
比较,所以我运行了数字sum
通常排在最前面(通常约20%),我认为它是可读性最好的。
p.port_stocks.reduce(0) do |sum, port_stock|
sum + (port_stock.volume * port_stock.purchase_price)
end
p.port_stocks.map{|ps| ps.volume * ps.purchase_price}.sum