[英]How to return List of objects containing aggregated (rising) sum of following elements with C# Enumerable.Aggregate method?
我有 ObjectA 類,其屬性稱為Value 。
我還有一個名為Sum的 ObjectB 類。
然后我有 List<ObjectA> listA。
如何從 C# Enumerable.Aggregate 方法返回 List<ObjectB> listB,其中每個后續 ObjectB 的屬性總和是來自 List<ObjectA> 的屬性值的(上升)聚合總和?
預期行為:
IN:具有以下屬性的 ObjectA 列表 Value {1,2,3,4,5,6}
OUT:具有以下屬性的 ObjectB 列表 Sum {1,3,6,10,15,21}
簡短的回答:不要。 請改用 Select 或循環。
長答案:
Aggregate
適用於您從值列表開始但希望以單個值結束的情況。 您試圖以另一個集合結束,每個輸入都有一個值。
這並不是說它不能完成。 僅出於學術目的,讓我們看一下您可以使用的一些模式。 我打算將問題簡化為只使用整數而不是ObjectA
和ObjectB
。
這可能是最“純粹”的方法,因為您傳遞給 Aggregate 的委托沒有副作用。
var values = new[]{1,2,3,4,5,6};
var sums = values.Aggregate(Enumerable.Empty<int>(), (previous, next) => previous.Append(previous.LastOrDefault() + next)).ToList();
但是,這可能具有O(n²)
復雜性,因為您在通過Append
調用鏈接在一起構造的IEnumerable<>
上調用LastOrDefault()
。 最好通過關閉運行總變量來接受一點雜質。
var values = new[]{1,2,3,4,5,6};
int runningTotal = 0;
var sums = values.Aggregate(Enumerable.Empty<int>(), (previous, next) => previous.Append(runningTotal += next)).ToList();
但是,如果我們願意以這種方式跟蹤狀態,那么只需使用Select
而不是Aggregate
,事情就會簡單得多:
int runningTotal = 0;
var sums = values.Select(next => runningTotal += next).ToList();
當然,純粹主義者會說像 LINQ 語句這樣的函數式語法不應該有副作用。 只構建一個具有更命令式的 foreach 循環的新列表可能會更清楚。
var values = new[]{1,2,3,4,5,6};
var sums = new List<int>();
int runningTotal = 0;
foreach(var next in values)
{
runningTotal += next;
sums.Add(runningTotal);
}
您可以通過以下方式進行Aggregate
:
var objectBs = objectAs
.Aggregate<ObjectA, IEnumerable<ObjectB>>(
Enumerable.Empty<ObjectB>(),
(objectBs, objectA) => objectBs.Append(new ObjectB
{
Sum = (objectBs.LastOrDefault()?.Sum ?? 0) + objectA.Value
}));
但這對人們來說很難閱讀(我個人就是這樣)。 或者,用 for 循環編寫它:
var listOfObjectBs = new List<ObjectB>
{
new ObjectB
{
Sum = objectAs.First().Value
}
};
for (var i = 1; i < objectAs.Count; i++)
{
listOfObjectBs.Add(new ObjectB
{
Sum = listOfObjectBs[i - 1].Sum + objectAs[i].Value
});
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.