Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LINQ sum collection of items to return object with results (multiple columns)

Tags:

c#

linq

I know I can do the below with a foreach but was wondering if there is a clean and "sexier" way of doing this with LINQ.

public class item
{
    public int total { get; set; }
    public int net { get; set; }
}


class Program
{
    static void Main(string[] args)
    {
        List<item> items = new List<item>()
                               {
                                   new item() { total = 123, net = 423},
                                   new item() { total = 432, net = 54},
                                   new item() { total = 33, net = 57654},
                                   new item() { total = 33, net = 423},
                                   new item() { total = 3344, net = 423},
                                   new item() { total = 123, net = 423},
                                   new item() { total = 123, net = 98},
                                   new item() { total = 123, net = 867},
                                   new item() { total = 123, net = 876},
                                   new item() { total = 123, net = 423},
                                   new item() { total = 123, net = 543},
                                   new item() { total = 543, net = 345},
                               };

        item i = new item();
        foreach (var item in items)
        {
            i.net += item.net;
            i.total += item.total;
        }
    }
}

What I would like to do is, for a given list of objects sum each of the columns / fields and return one single object with the sum of each value.

I tried:

var result = (from e in items
                     select new
                                {
                                    NET_GRAND = e.net,
                                    TOTAL_GRAND = e.total
                                }).ToList();

And variations on the below but with no luck:

 var result = (from t in items
                     group t by new {t.net, t.total}
                     into grp
                     select new
                                {
                                    NET_GRAND = grp.Sum(t => t.net),
                                    TOTAL_GRAND = grp.Sum(t => t.total)
                                }).GroupBy(x => new { x.NET_GRAND, x.TOTAL_GRAND }).ToList();

EDIT

should have pointed out that efficiency is important here as well as sexiness.

like image 844
Jon Avatar asked Dec 12 '11 12:12

Jon


2 Answers

If you don't care about iterating the list twice,

var i = new item
    { 
        net = items.Sum(it => it.net), 
        total = items.Sum(it => it.total) 
    };

If you do care about iterating the list twice (as you might be if you were doing this for an IEnumerable of unknown origin),

var i = items.Aggregate(new item(), 
    (accumulator, it) => 
        new item 
        {
            net = accumulator.net + it.net, 
            total = accumulator.total + it.total 
        } 
);
like image 190
AakashM Avatar answered Sep 20 '22 13:09

AakashM


It looks like you really want:

var result = new {
    NetGrand = items.Sum(t => t.net),
    TotalGrand = items.Sum(t => t.total)
};

On the other hand, I'd probably just separate those into two different local variables:

var netGrand = items.Sum(t => t.net);
var totalGrand = items.Sum(t => t.total);

Of course this iterates over the list twice, but in most cases I'd expect that not to be noticeable.

like image 21
Jon Skeet Avatar answered Sep 20 '22 13:09

Jon Skeet