19 Stimmen

C#: Wie man die Methode Enumerable.Aggregate verwendet

Sagen wir, ich lasse mir das amputieren Person Klasse:

class Person
{
    public int Age { get; set; }
    public string Country { get; set; }

    public int SOReputation { get; set; }
    public TimeSpan TimeSpentOnSO { get; set; }

    ...
}

Ich kann dann gruppieren nach Age y Country wie diese:

    var groups = aListOfPeople.GroupBy(x => new { x.Country, x.Age });

Dann kann ich alle Gruppen mit ihren Rufsummen wie folgt ausgeben:

foreach(var g in groups)
    Console.WriteLine("{0}, {1}:{2}", 
        g.Key.Country, 
        g.Key.Age, 
        g.Sum(x => x.SOReputation));

Meine Frage ist, wie kann ich eine Summe der TimeSpentOnSO Eigentum? Die Sum Methode wird in diesem Fall nicht funktionieren, da sie nur für int und so weiter. Ich dachte, ich könnte die Aggregate Methode, aber ich kann einfach nicht herausfinden, wie man sie benutzt... Ich versuche alle Arten von Eigenschaften und Typen in verschiedenen Kombinationen, aber der Compiler wird einfach nicht erkennen, es.

foreach(var g in groups)
    Console.WriteLine("{0}, {1}:{2}", 
        g.Key.Country, 
        g.Key.Age, 
        g.Aggregate(  what goes here??  ));

Habe ich die Aggregate-Methode völlig missverstanden? Oder was ist hier los? Sollte ich stattdessen eine andere Methode verwenden? Oder muss ich meine eigene Methode schreiben? Sum Variante für TimeSpan s?

Und um das Durcheinander noch zu vergrößern, was ist, wenn Person eine anonyme Klasse ist, ein Ergebnis von zum Beispiel einer Select oder eine GroupJoin Aussage?


Ich habe gerade herausgefunden, dass ich die Aggregate Methode funktionieren, wenn ich eine Select über die TimeSpan Eigentum zuerst... aber ich finde das irgendwie nervig... Ich habe immer noch nicht das Gefühl, dass ich diese Methode überhaupt verstehe...

foreach(var g in groups)
    Console.WriteLine("{0}, {1}:{2}", 
        g.Key.Country, 
        g.Key.Age, 
        g.Select(x => x.TimeSpentOnSO)
        g.Aggregate((sum, x) => sum + y));

24voto

Daniel Brückner Punkte 57561
List<TimeSpan> list = new List<TimeSpan>
    {
        new TimeSpan(1),
        new TimeSpan(2),
        new TimeSpan(3)
    };

TimeSpan total = list.Aggregate(TimeSpan.Zero, (sum, value) => sum.Add(value));

Debug.Assert(total.Ticks == 6);

14voto

Chris Doggett Punkte 18701
g.Aggregate(TimeSpan.Zero, (i, p) => i + p.TimeSpentOnSO)

Im Grunde ist das erste Argument von Aggregate ein Initialisierungswert, der als erster Wert von "i" in der Funktion verwendet wird, die im zweiten Argument übergeben wird. Es wird die Liste durchlaufen, und jedes Mal enthält "i" die bisherige Gesamtzahl.

Zum Beispiel:

List<int> nums = new List<int>{1,2,3,4,5};

nums.Aggregate(0, (x,y) => x + y); // sums up the numbers, starting with 0 => 15
nums.Aggregate(0, (x,y) => x * y); // multiplies the numbers, starting with 0 => 0, because anything multiplied by 0 is 0
nums.Aggregate(1, (x,y) => x * y); // multiplies the numbers, starting with 1 => 120

2voto

Marc Gravell Punkte 970173

Sie könnten schreiben TimeSpan Sum Methode...

public static TimeSpan Sum(this IEnumerable<TimeSpan> times)
{
    return TimeSpan.FromTicks(times.Sum(t => t.Ticks));
}
public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source,
    Func<TSource, TimeSpan> selector)
{
    return TimeSpan.FromTicks(source.Sum(t => selector(t).Ticks));
}

Alternativ dazu, MiscUtil hat generic-aktiviert Sum Methoden, also Sum sollte bei einer TimeSpan gut (da es eine TimeSpan+TimeSpan=>TimeSpan Operator definiert).

Einfach bitte Sagen Sie mir nicht die Nummer... das würde mir Angst machen...

2voto

Svish Punkte 144948

Eine Kombination aus den Antworten von Chris und Daniels hat das Problem für mich gelöst. Ich musste die TimeSpan initialisieren, und ich tat Dinge in der falschen Reihenfolge. Die Lösung ist:

foreach(var g in groups)
    Console.WriteLine("{0}, {1}:{2}", 
        g.Key.Country, 
        g.Key.Age, 
        g.Aggregate(TimeSpan.Zero, (sum, x) => sum + x.TimeSpentOnSO));

Gracias.

Und außerdem... Oh, Gott!

0voto

Joseph Punkte 24916

Sie könnten die Summe über eine der Total-Eigenschaften des TimeSpan bilden. So könnten Sie zum Beispiel die dargestellten Gesamtstunden der für SO aufgewendeten Zeit erhalten:

g.Sum(x => x.SOReputation.TotalHours)

Ich glaube, dass Sie damit das gewünschte Ergebnis erhalten, allerdings mit dem Vorbehalt, dass Sie die Maßeinheiten je nach Bedarf eingeben müssen (Stunden, Minuten, Sekunden, Tage usw.).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X