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.

Odpowiedzi:


310
using System.Linq;

...

double total = myList.Sum(item => item.Amount);

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

11

Inna alternatywa:

myPlanetsList.Select(i => i.Moons).Sum();

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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.