Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sum a collection of objects which contain numeric properties only with LINQ

Tags:

c#

.net

linq

I have an object model like this:

public class Quantity
{
    public decimal Weight { get; set; }
    public decimal Volume { get; set; }
    // perhaps more decimals...

    public static Quantity operator +(Quantity quantity1, Quantity quantity2)
    {
        return new Quantity()
        {
            Weight = quantity1.Weight + quantity2.Weight,
            Volume = quantity1.Volume + quantity2.Volume
        };
    }
}

public class OrderDetail
{
    public Quantity Quantity { get; set; }
}

public class Order
{
    public IEnumerable<OrderDetail> OrderDetails { get; set; }
}

Now I want to introduce a readonly property TotalQuantity on the Order class which should sum up the quantities of all OrderDetails.

I am wondering if there is better "LINQ way" than this:

public class Order
{
    // ...
    public Quantity TotalQuantity
    {
        get
        {
            Quantity totalQuantity = new Quantity();
            if (OrderDetails != null)
            {
                totalQuantity.Weight =
                    OrderDetails.Sum(o => o.Quantity.Weight);
                totalQuantity.Volume =
                    OrderDetails.Sum(o => o.Quantity.Volume);
            }
            return totalQuantity;
        }
    }
}

It's not a nice solution as it iterates twice through the OrderDetails. And something like this is not supported (even though a + operator is provided in the Quantity class):

Quantity totalQuantity = OrderDetails.Sum(o => o.Quantity); // doesn't compile

Is there a better way to build the total sum in LINQ?

(Just for theoretical interest, a simple foreach loop would also do its job well of course.)

Thanks for feedback!

like image 997
Slauma Avatar asked Apr 10 '11 15:04

Slauma


1 Answers

Try:

OrderDetails.Select(o => o.Quantity).Aggregate((x, y) => x + y)

If you'd prefer not to have the overhead of the new Quantity object for each addition (RE comment), you could use something like:

new Quantity {
    Weight = OrderDetails.Select(o => o.Quantity.Weight).Sum(),
    Volume = OrderDetails.Select(o => o.Quantity.Volume).Sum()
};

Not as nice as the first one, and slightly more awkward (and slower?) than just the plain foreach loop.

You can find more about the Aggregate() method on MSDN.

like image 77
Lucas Jones Avatar answered Nov 16 '22 19:11

Lucas Jones