如何在Rails中的多个对象之间求和两个值的乘积?

时间:2018-05-15 08:02:23

标签: ruby-on-rails ruby ruby-on-rails-5

想象一下,我的投资组合p有2只股票port_stocks。我想要做的是对每个port_stock运行计算,然后总结所有结果。

[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)> 

所以,实质上,使用上面的代码我想这样做:

ps = p.port_stocks.first #(`id=17`)
first = ps.volume * ps.purchase_price # 2000 * 5.9 = 11,800

ps = p.port_stocks.second #(`id=18`)
second = ps.volume * ps.purchase_price # 1000 * 9.0 = 9,000

first + second = 19,800

我想简单地获得19,800。理想情况下,我想以非常Ruby的方式做到这一点。

如果我只是简单地总结1 total_spend中的所有值,我知道我可以这样做:p.port_stocks.map(&:total_spend).sum那就是那个。

但是当我第一次对每个对象进行数学运算时,不确定如何做类似的事情,然后将所有对象中的所有产品相加。这显然适用于2个对象或500个。

2 个答案:

答案 0 :(得分:6)

使用Rails执行此操作的最佳方法是将块传递给 stream = new MemoryStream(); // read xml in memory writer = new StreamWriter(stream, Encoding.Unicode); // get serialise object XmlSerializer serializer = new XmlSerializer(typeof(Test)); serializer.Serialize(writer, emp); // read object int count = (int)stream.Length; // saves object in memory stream byte[] arr = new byte[count]; stream.Seek(0, SeekOrigin.Begin); // copy stream contents in byte array stream.Read(arr, 0, count); UnicodeEncoding utf = new UnicodeEncoding(); // convert byte array to string return utf.GetString(arr).Trim(); ,如下所示:

sum

使用专用于总计数字的方法,并且往往非常快速和有效 - 特别是与在没有阻塞的情况下调用直接p.port_stocks.sum do |port_stock| port_stock.volume * port_stock.purchase_price end 之前操纵数据相比。

快速基准here通常表明它比明显的替代品快了约20%。

我无法测试,但试一试,它应该为您解决。

让我知道你是怎么过的!

只是一个快速更新,因为你还提到了最好的Ruby方式,sumintroduced in 2.4,但是在旧版本的Ruby上你可以使用reduce(也别名为sum }):

inject

这并不像p.port_stocks.reduce(0) do |sum, port_stock| sum + (port_stock.volume * port_stock.purchase_price) end 那样有效,但我想我会给你选择:)

答案 1 :(得分:2)

使用Array#map迭代所有股票是正确的,但是要将所有total_spend值相加,您可以为每个股票计算它。之后,您将所有结果和完成结果相加:

p.port_stocks.map{|ps| ps.volume * ps.purchase_price}.sum

或者你可以像SRack那样使用Enumerable#reduce。这将通过一步/迭代返回结果。