# LINQ Sumar todas las propiedades

¿Existe una forma elegante de hacer esto?

Assume I am working with objects that have excusively numeric properties (ints and doubles), like this:

``````Foo
-bar1 int
-bar2 int
-bar3 int
-foobar1 double
-foobar2 double
``````

and I have a collection of List...is there a way to have it simply sum all the numeric properties in the List and return a single object Foo with all the totals?

thanks as always SO

preguntado el 04 de septiembre de 13 a las 02:09

I am trying to verify if I understood your question correctly. Do you want to obtain a single `Foo` instance of which each member value is the sum of corresponding member for a set of `Foo` instances that are in a list? -

this should be done with simple `For loop`, sometimes if you try to do it using `LINQ`, we may have to end up using `ForEach` method or something like that. -

## 3 Respuestas

If I understood your question correctly, and you want to get one `Foo` instance, in which each member is the sum of all the corresponding members of `Foo` instances that are present in a list, then one possible (somewhat verbose, but straightforward no magic involved) way is to use linq Aggregate:

``````// Simplified Foo to prevent a lot of typing.
public class Foo
{
public int bar1 { get; set; }
public int bar2 { get; set; }
public double foobar1 { get; set; }
}

var myFooList = new List<Foo>
{
new Foo() { bar1 = 1, bar2 = 2, foobar1 = 20.0 },
new Foo() { bar1 = 5, bar2 = 8, foobar1 = 42.0 },
new Foo() { bar1 = 9, bar2 = 3, foobar1 = -10.0 },
};
var myFooSum = myFooList.Aggregate(new Foo(), (curSum, foo) =>
{
curSum.bar1 += foo.bar1;
curSum.bar2 += foo.bar2;
curSum.foobar1 += foo.foobar1;
return curSum;
});
Console.WriteLine("FooSum: bar1 = {0}, bar2 = {1}, bar3 = {2}", myFooSum.bar1, myFooSum.bar2, myFooSum.foobar1);
``````

Huellas dactilares:

``````FooSum: bar1 = 15, bar2 = 13, bar3 = 52
``````

If I misunderstood, and you want so sum an arbitrary list of objects, some of which may contain multiple numerical fields, into a single sum value an approach such as suggested by @Simon Whitehead could work:

``````public class Bar
{
public int baz { get; set; }
public double booz { get; set; }
public string nonNumeric { get; set; }
}

static double SumNumericalProperties(object obj)
{
if (obj == null)
return 0;
if (obj is int)
return (int)obj;
if (obj is double)
return (double)obj;
// etc for other numeric types.

var sum = 0.0;
foreach (var prop in obj.GetType().GetProperties())
{
if (typeof(int).IsAssignableFrom(prop.PropertyType))
sum += (int)prop.GetValue(obj);
else if (typeof(double).IsAssignableFrom(prop.PropertyType))
sum += (double)prop.GetValue(obj);
// etc for other numeric types.
}
return sum;
}

var myObjectList = new List<object>
{
new Foo() { bar1 = 1, bar2 = 2, foobar1 = 20.0 },
new Bar() { baz = 10, booz = 100.0 },
24,
33.3333,
new Foo() { bar1 = 5, bar2 = 8, foobar1 = 42.0 },
new Foo() { bar1 = 9, bar2 = 3, foobar1 = -10.0 },
};

var myFooSum = myObjectList.Sum(SumNumericalProperties);
Console.WriteLine("Sum = {0}", myFooSum);
``````

Que imprime:

``````Sum = 247.3333
``````

Respondido el 04 de Septiembre de 13 a las 03:09

No creo que hayas entendido la pregunta. - Erik Funkenbusch

I think this is what the OP wants. Only 2 phrases can show that, return single Foo y all the totals - Rey rey

It can also be done using this one-liner :-)

``````Item sum = (from p in typeof(Item).GetFields()
where Type.GetTypeCode(p.FieldType) == TypeCode.Int32 || Type.GetTypeCode(p.FieldType) == TypeCode.Double
group p by p into g
select new { Prop=g.Key, Sum=items.Sum(s => (decimal)Convert.ChangeType(g.Key.GetValue(s), TypeCode.Decimal)) })
.Aggregate(new Item(), (state, next) => {
next.Prop.SetValue(state, Convert.ChangeType(next.Sum, next.Prop.FieldType));
return state;
});
``````

Muestra completa:

``````using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
class Item
{
public int bar1 = 0;
public int bar2 = 0;
public double foobar1 = 0;
public double foobar2 = 0;
}

public static void Main ()
{
var items = new List<Item>();
items.Add(new Item() { bar1 = 1, bar2 = 2, foobar1 = 1.1, foobar2 = 1.2 });
items.Add(new Item() { bar1 = 1, bar2 = 2, foobar1 = 1.1, foobar2 = 1.2 });
items.Add(new Item() { bar1 = 1, bar2 = 2, foobar1 = 1.1, foobar2 = 1.2 });

var sum = (from p in typeof(Item).GetFields()
where Type.GetTypeCode(p.FieldType) == TypeCode.Int32 || Type.GetTypeCode(p.FieldType) == TypeCode.Double
group p by p into g
select new { Prop=g.Key, Sum=items.Sum(s => (decimal)Convert.ChangeType(g.Key.GetValue(s), TypeCode.Decimal)) })
.Aggregate(new Item(), (state, next) => {
next.Prop.SetValue(state, Convert.ChangeType(next.Sum, next.Prop.FieldType));
return state;
});

Console.WriteLine("bar1: " + sum.bar1);
Console.WriteLine("bar2: " + sum.bar2);
Console.WriteLine("foobar1: " + sum.foobar1);
Console.WriteLine("foobar2: " + sum.foobar2);
}
}
``````

Respondido el 04 de Septiembre de 13 a las 04:09

ding ding, we have a winner! Thank you for taking the time to understand the question and provide an elegant answer, that was exactly what I was looking for. Also you anticipated the next issue which was objects that might have mixed types (numeric and strings for example) - snappymcsnap

Rough attempt:

``````    private static double sumNumericalProperties<T>(T obj)
{
var result = 0d;

foreach (var prop in typeof (T).GetProperties())
{
if (typeof(int).IsAssignableFrom(prop.PropertyType))
{
result += (int)prop.GetValue(obj);
}
else if (typeof(double).IsAssignableFrom(prop.PropertyType))
{
result += (double) prop.GetValue(obj);
}
}

return result;
}
``````

``````class Foo
{
public int Bar1 { get; set; }
public int Bar2 { get; set; }
public double Foobar1 { get; set; }
public double Foobar2 { get; set; }
public string BufferProperty { get; set; }
}

var obj = new Foo() {Bar1 = 2, Bar2 = 4, Foobar1 = 5, Foobar2 = 6};
var obj2 = new Foo() { Bar1 = 2, Bar2 = 4, Foobar1 = 5, Foobar2 = 7 };

var list = new List<Foo>();