Lista obiektów w C #, jak uzyskać sumę właściwości

158

Mam listę obiektów. Jedną z właściwości pojedynczego wpisu obiektu jest kwota. Jak uzyskać sumę kwoty?

Jeśli moja lista była typu double, być może uda mi się zrobić coś takiego:

double total = myList.Sum();

Jednak chcę coś podobnego, ale ta składnia jest niepoprawna.

double total = myList.amount.Sum();

Jak mam się do tego zabrać? Chciałbym, jeśli to możliwe, użyć funkcji Sum zamiast przechodzenia po pętli i obliczania wartości.

Joseph U.
źródło

Odpowiedzi:

310
using System.Linq;

...

double total = myList.Sum(item => item.Amount);
Alex LE
źródło
12
Czy jest to szybsze niż zawsze z powodu zainteresowania?
Coops
4
Interesuje mnie również pytanie @ CodeBlend. Czy to obliczenie będzie szybsze niż pętla for?
rex
23
@Coops - Aby odpowiedzieć na twoje pytanie ... używając listy zawierającej 100 000 obiektów, każdy obiekt mający pojedynczą właściwość typu danych double, sumując właściwość 1000 razy za pomocą powyższego rozwiązania (myList.Sum) zajmuje 2,44 sekundy w porównaniu do 0,98 sekundy przy użyciu foreach . Upływający czas jest mierzony za pomocą klasy Stopwatch dla dokładności. Dlatego foreach jest ponad 2x szybsze niż użycie myList.Sum.
Joe Gayetty
36

A jeśli musisz to zrobić na przedmiotach, które spełniają określony warunek ...

double total = myList.Where(item => item.Name == "Eggs").Sum(item => item.Amount);
Greg Quinn
źródło
11

Inna alternatywa:

myPlanetsList.Select(i => i.Moons).Sum();
przydatne
źródło
5
Zamiast .Select(i => i.Moons).Sum()ciebie możesz użyć.Sum(i => i.Moons)
Mason
1
@Mason, zgadza się i tak Alex podszedł do problemu w swojej wcześniejszej odpowiedzi, więc podałem inny sposób zrobienia tego samego.
przydatneBee
1
Ach tak, przepraszam za moje błędne przekonanie.
Mason
Doceniam, że to wyjątkowa odpowiedź, ale czy wydajność nie ucierpi?
Peter Lenjo
2

Oto przykładowy kod, który możesz uruchomić, aby wykonać taki test:

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

Ten sam przykład dla złożonego obiektu to:

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

Moje wyniki z wyłączoną optymalizacją kompilatora to:

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

a dla drugiego testu to:

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

wygląda na to, że LINQ jest generalnie wolniejszy niż foreach (...), ale dla mnie dziwne jest to, że foreach (...) wydaje się być szybsze niż pętla for.

Puchacz
źródło
2
dla odniesienia w przyszłości, spojrzeć Stopwatchw System.Diagnosticsjak to jest rejestrator czasu o wysokiej wydajności. (Przy okazji nie przegłosowałem)
Meirion Hughes,
1
Nie używać DateTime.Nowdo pomiaru. Ma fatalną wydajność, ponieważ zawsze zwraca czas lokalny. DateTime.UtcNowjest szybszy; jednak nadal nie używa tak wysokiej rozdzielczości jak Stopwatchklasa.
György Kőszeg
3
To nie odpowiada na pytanie.
Mark Pattison,
Ok, dzięki za napiwek. Wyniki są bardzo powtarzalne, więc założyłem, że taka rozdzielczość wystarczy
Puchacz
2
Chociaż twój zamiar jest dobry - Mark ma rację - nie odpowiadasz wprost na pytanie. Radziłbym zmienić to na: „Oto, jak możesz to zrobić” i „Oto wydajność procesora każdej opcji”. W zasadzie, jeśli opisujesz swoją metodologię testowania, nie musisz nam pokazywać kodu.
Meirion Hughes