开发者

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)
                        }
);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜