C # Lista de objetos, ¿cómo obtengo la suma de una propiedad?

158

Tengo una lista de objetos. Una propiedad de la entrada de objeto individual es la cantidad. ¿Cómo obtengo la suma de la cantidad?

Si mi lista era de tipo doble, podría hacer algo como esto:

double total = myList.Sum();

Sin embargo, quiero algo similar a esto, pero esta sintaxis es incorrecta.

double total = myList.amount.Sum();

¿Cómo debo hacer para lograr esto? Me encantaría usar la función Suma si es posible en lugar de recorrer y calcular el valor.

Joseph U.
fuente

Respuestas:

310
using System.Linq;

...

double total = myList.Sum(item => item.Amount);
Alex LE
fuente
12
¿Es esto más rápido que foreach por interés?
Coops
44
También estoy interesado en la pregunta de @ CodeBlend. ¿Será este cálculo más rápido que un bucle for?
rex
23
@Coops: para responder a su pregunta ... usando una lista que contiene 100,000 objetos, cada objeto tiene una sola propiedad de tipo de datos doble, resumiendo la propiedad 1,000 veces usando la solución anterior (myList.Sum) toma 2.44 segundos en comparación con 0.98 segundos usando foreach . El tiempo transcurrido se mide utilizando la clase de cronómetro para mayor precisión. Por lo tanto, foreach es más de 2 veces más rápido que usar myList.Sum.
Joe Gayetty
36

Y si necesita hacerlo en artículos que coinciden con una condición específica ...

double total = myList.Where(item => item.Name == "Eggs").Sum(item => item.Amount);
Greg Quinn
fuente
11

Otra alternativa:

myPlanetsList.Select(i => i.Moons).Sum();
útilBee
fuente
55
En lugar de .Select(i => i.Moons).Sum()que pueda usar.Sum(i => i.Moons)
Mason
1
@Mason, correcto, y así es como Alex abordó el problema en su respuesta anterior, así que simplemente proporcioné una forma diferente de hacer lo mismo.
útilBee
1
Ah sí, perdón por mi error.
Mason
Aprecio que esta sea una respuesta única, pero ¿no se vería afectado el rendimiento?
Peter Lenjo
2

Aquí hay un código de ejemplo que puede ejecutar para realizar dicha prueba:

var f = 10000000;
var p = new int[f];

for(int i = 0; i < f; ++i)
{
    p[i] = i % 2;
}

var time = DateTime.Now;
p.Sum();
Console.WriteLine(DateTime.Now - time);

int x = 0;
time = DateTime.Now;
foreach(var item in p){
   x += item;
}
Console.WriteLine(DateTime.Now - time);

x = 0;
time = DateTime.Now;
for(int i = 0, j = f; i < j; ++i){
   x += p[i];
}
Console.WriteLine(DateTime.Now - time);

El mismo ejemplo para objeto complejo es:

void Main()
{
    var f = 10000000;
    var p = new Test[f];

    for(int i = 0; i < f; ++i)
    {
        p[i] = new Test();
        p[i].Property = i % 2;
    }

    var time = DateTime.Now;
    p.Sum(k => k.Property);
    Console.WriteLine(DateTime.Now - time);

    int x = 0;
    time = DateTime.Now;
    foreach(var item in p){
        x += item.Property;
    }
    Console.WriteLine(DateTime.Now - time);

    x = 0;
    time = DateTime.Now;
    for(int i = 0, j = f; i < j; ++i){
        x += p[i].Property;
    }
    Console.WriteLine(DateTime.Now - time);
}

class Test
{
    public int Property { get; set; }
}

Mis resultados con las optimizaciones del compilador desactivadas son:

00:00:00.0570370 : Sum()
00:00:00.0250180 : Foreach()
00:00:00.0430272 : For(...)

y para la segunda prueba son:

00:00:00.1450955 : Sum()
00:00:00.0650430 : Foreach()
00:00:00.0690510 : For()

parece que LINQ es generalmente más lento que foreach (...) pero lo que es extraño para mí es que foreach (...) parece ser más rápido que para loop.

Puchacz
fuente
2
para futuras referencias, echar un vistazo a Stopwatchen System.Diagnosticsque se trata de un registrador de tiempo de alto rendimiento. (No te rechacé por cierto)
Meirion Hughes
1
No utilizar DateTime.Nowpara medir. Tiene un rendimiento terrible, ya que regresa siempre a la hora local. DateTime.UtcNowes más rápido; sin embargo, todavía no usa tan alta resolución como la Stopwatchclase.
György Kőszeg
3
Esto no responde la pregunta.
Mark Pattison
Ok, gracias por la propina. Los puntajes son muy repetibles, así que supuse que tal resolución es suficiente
Puchacz
2
Si bien su intención es buena -Mark tiene razón- no está respondiendo explícitamente la pregunta. Te recomiendo que lo cambies a: "Aquí es cómo puedes hacerlo" y "Aquí está el rendimiento de la CPU de cada opción". También, en principio, si describe su metodología de prueba, no necesita mostrarnos el código.
Meirion Hughes