想象一下,我的投资组合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个。
答案 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方式,sum
是introduced 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。这将通过一步/迭代返回结果。