How can I get running totals of integer values from a List()?
List has object which has properties as开发者_运维问答 follows :
public class PropertyDetails
{
public int Sequence { get; set; }
public int Length { get; set; }
public string Type { get; set; }
public int Index { get; set; }
}
List will have sorted Sequence .
List has object values as follows:
Sequence= 1 Length=20 Type="" Index=0
Sequence= 2 Length=8 Type="" Index=0
Sequence= 3 Length=6 Type="" Index=0
Sequence= 4 Length=20 Type="" Index=0
Sequence= 5 Length=8 Type="" Index=0
I want Linq query which will give me result List as
Sequence= 1 Length=20Type="" Index=20
Sequence= 2 Length=8 Type="" Index=28
Sequence= 3 Length=6 Type="" Index=34
Sequence= 4 Length=20 Type="" Index=54
Sequence= 5 Length=8 Type="" Index=62
Where index is cumulative sum of Length considering sequence.
I never though I'd say this, but I find Jon's solution to be overengineering. Rather, I find LINQ to be the wrong solution for this problem. You want to manipulate state, not a good fit for traditional LINQ-operators.
I'd just do this:
var sum = 0;
foreach (var p in list) {
sum += p.Length;
p.Index = sum;
}
LINQ is a hammer. Make sure you use the right tool for the problem, instead of just asking for hammering-advice.
There's no standard LINQ operator which does this - basically you want a running aggregation. You can fake it with a query with side-effects at the moment, but that's it.
Fortunately, it's easy to write your own query operator to do this. Something like:
public static IEnumerable<TResult> Scan<TSource, TResult>(
this IEnumerable<TSource> source,
TResult seed,
Func<TResult, TSource, TResult> func)
{
TResult current = seed;
// TODO: Argument validation
foreach (TSource item in source)
{
current = func(current, item);
yield return current;
}
}
Then you can use:
var query = list.Scan(new PropertyDetails(),
(current, item) => new PropertyDetails {
Sequence = item.Sequence,
Length = item.Length,
Index = current.Index + item.Length
});
EDIT: I haven't checked the details, but I believe Reactive Extensions has a similar method in its System.Interactive assembly.
Maybe something like this (it's not very readable):
var newList = list.Select(x =>
new PropertyDetails()
{
Type = x.Type,
Length = x.Length,
Sequence = x.Sequence,
Index = list.Take(x.Sequence).Select(y => y.Length).Aggregate((a, b) => a + b)
}
);
精彩评论