LINQ到对象,如何在适当的地方更新列表中的项
本文关键字:方更新 更新 列表 LINQ 对象 | 更新日期: 2023-09-27 18:17:43
我目前有以下工作代码。然而,它的速度慢得令人痛苦。我知道以查询而不是以列表的形式传递数据可能会简化和加快速度,但由于各种原因,这是不可能的。
如何在不创建新列表的情况下更新现有的持有列表?还有其他改进代码的建议吗?
internal List<DailyHoldingItem> TransformHoldingItemsToCurrency(List<DailyHoldingItem> holdings,string toCurrency)
{
//TODO - how to do this calculation in place, without creating a new list?
var query = (from holding in holdings
from fxRateHolding in amdw.FXRates
from fxRateToCur in amdw.FXRates
where
fxRateHolding.BaseCurrency == holding.Currency &&
fxRateToCur.BaseCurrency == toCurrency &&
fxRateHolding.ValueDate == holding.Date &&
fxRateToCur.ValueDate == holding.Date
select new { holding, fxRateHolding, fxRateToCur });
return query.Select(dhi =>
{
decimal factor = dhi.fxRateToCur.Value / dhi.fxRateHolding.Value;
dhi.holding.MarketValue *= factor;
dhi.holding.Fee *= factor;
dhi.holding.Remuneration *= factor;
return dhi.holding;
}).ToList();
}
首先,你可以使用连接来加快速度,并且只评估一次有效的"目标"货币:
var targetRates = amdw.FXRates
.Where(rate => rate.BaseCurrency == toCurrency)
.ToList();
var query = from holding in holdings
join fxRateHolding in amdw.FXRates
on new { holding.Currency, holding.Date } equals
new { Currency = fxRateHolding.BaseCurrency,
Date = fxRateHolding.ValueDate }
join fxRateToCur in targetRates
on holding.Date equals fxRateToCur.ValueDate
select new { holding, fxRateHolding, fxRateToCur };
就我个人而言,我不会尝试就地更新列表,我不会改变现有的持有(正如您目前在Select
呼叫中所做的那样)。改变现有的值往往会使你的代码更难推理——这就是为什么LINQ 被设计成以更实用的方式使用。
在更新对象时不应该使用LINQ。LINQ应该是没有副作用的,你应该用它来获得你想要改变的项目,然后对它们做一个foreach。
foreach(var dhi in query)
{
decimal factor = dhi.fxRateToCur.Value / dhi.fxRateHolding.Value;
dhi.holding.MarketValue *= factor;
dhi.holding.Fee *= factor;
dhi.holding.Remuneration *= factor;
}
您也可以像这样使用在List<T>
上定义的ForEach函数。
query.ToList().ForEach(dhi =>
{
decimal factor = dhi.fxRateToCur.Value / dhi.fxRateHolding.Value;
dhi.holding.MarketValue *= factor;
dhi.holding.Fee *= factor;
dhi.holding.Remuneration *= factor;
});
就像Jeff Mercado在评论中指出的那样,仅仅把ForEach()
命名为列表并不是一个好主意。
你可以在SQL中做到这一点,只是要注意不是每个人都希望LINQ产生副作用,但毕竟c#不是一种函数式语言。
你可以这样做:
-
要更新单个属性,只需执行:
from a in ab select a.prop = newVal;
-
要更新多个属性,您有以下选项:
-
将更新拆分为多个LINQ查询,每个查询更新一个属性(显然不是最好的主意)
-
执行
from a in ab select new { x = a.prop = newVal, y = a.prop2 = newVal2 };
-
在LINQ方法链中(但不是在查询表达式中),您可以执行
ab.Select( a=> { x = a.prop = newVal; y = a.prop2 = newVal2; return x; };
(实际上,在Linq to objects Update中,有一个建议将最后一个方法重构为一个扩展方法,这将允许它在查询表达式中使用,并澄清意图)
-