C # Liste der Objekte, wie erhalte ich die Summe einer Eigenschaft?

158

Ich habe eine Liste von Objekten. Eine Eigenschaft des einzelnen Objekteintrags ist der Betrag. Wie bekomme ich die Summe?

Wenn meine Liste vom Typ double wäre, könnte ich möglicherweise Folgendes tun:

double total = myList.Sum();

Ich möchte jedoch etwas Ähnliches, aber diese Syntax ist falsch.

double total = myList.amount.Sum();

Wie soll ich das erreichen? Ich würde gerne die Summenfunktion verwenden, wenn dies möglich ist, anstatt den Wert zu durchlaufen und zu berechnen.

Joseph U.
quelle

Antworten:

310
using System.Linq;

...

double total = myList.Sum(item => item.Amount);
Alex LE
quelle
12
Ist das schneller als aus Interesse?
Coops
4
Ich interessiere mich auch für die Frage von @ CodeBlend. Wird diese Berechnung schneller sein als eine for-Schleife?
Rex
23
@Coops - Um Ihre Frage zu beantworten ... unter Verwendung einer Liste mit 100.000 Objekten, wobei jedes Objekt eine einzelne Eigenschaft vom Datentyp double hat, dauert die 1.000-fache Summierung der Eigenschaft mit der obigen Lösung (myList.Sum) 2,44 Sekunden, verglichen mit 0,98 Sekunden mit foreach . Die verstrichene Zeit wird zur Genauigkeit mit der Stoppuhrklasse gemessen. Daher ist foreach mehr als doppelt so schnell wie myList.Sum.
Joe Gayetty
36

Und wenn Sie dies für Elemente tun müssen, die einer bestimmten Bedingung entsprechen ...

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

Eine andere Alternative:

myPlanetsList.Select(i => i.Moons).Sum();
nützlichBee
quelle
5
Anstelle von können .Select(i => i.Moons).Sum()Sie verwenden.Sum(i => i.Moons)
Mason
1
@Mason, richtig, und so ging Alex in seiner früheren Antwort an das Problem heran, also habe ich nur eine andere Möglichkeit angegeben, dasselbe zu tun.
nützlichBee
1
Ach ja, entschuldige mein Missverständnis.
Mason
Ich weiß zu schätzen, dass dies eine einzigartige Antwort ist, aber würde die Leistung nicht darunter leiden?
Peter Lenjo
2

Hier ist ein Beispielcode, den Sie ausführen können, um einen solchen Test durchzuführen:

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

Das gleiche Beispiel für ein komplexes Objekt ist:

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

Meine Ergebnisse mit deaktivierten Compiler-Optimierungen sind:

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

und für den zweiten Test sind:

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

Es sieht so aus, als ob LINQ im Allgemeinen langsamer ist als foreach (...), aber was für mich seltsam ist, ist, dass foreach (...) schneller zu sein scheint als for loop.

Puchacz
quelle
2
Schauen Sie sich zum späteren Nachschlagen Stopwatchin an, System.Diagnosticsda es sich um einen Hochleistungs-Zeitrekorder handelt. (Ich habe dich übrigens nicht abgelehnt)
Meirion Hughes
1
Nicht DateTime.Nowzum Messen verwenden. Es hat eine schreckliche Leistung, da es immer Ortszeit zurückgibt. DateTime.UtcNowist schneller; Es wird jedoch immer noch nicht so hoch aufgelöst wie die StopwatchKlasse.
György Kőszeg
3
Dies beantwortet die Frage nicht.
Mark Pattison
Ok, danke für den Tipp. Die Ergebnisse sind sehr wiederholbar, daher habe ich angenommen, dass eine solche Auflösung ausreicht
Puchacz,
2
Während Ihre Absicht gut ist - Mark ist richtig -, beantworten Sie die Frage nicht explizit. Ich würde empfehlen, dass Sie es in "Hier ist, wie Sie es tun können" und "Hier ist die CPU-Leistung jeder Option" ändern. Wenn Sie Ihre Testmethode beschreiben, müssen Sie uns den Code grundsätzlich nicht zeigen.
Meirion Hughes