LINQ Aggregate-Algorithmus erklärt

722

Das mag lahm klingen, aber ich konnte keine wirklich gute Erklärung dafür finden Aggregate.

Gut bedeutet kurz, beschreibend, umfassend mit einem kleinen und klaren Beispiel.

Alexander Beletsky
quelle

Antworten:

1015

Die am einfachsten zu verstehende Definition von Aggregateist, dass für jedes Element der Liste eine Operation ausgeführt wird, wobei die zuvor durchgeführten Operationen berücksichtigt werden. Das heißt, es führt die Aktion für das erste und zweite Element aus und überträgt das Ergebnis. Dann arbeitet es mit dem vorherigen Ergebnis und dem dritten Element und überträgt es. usw.

Beispiel 1. Zahlen summieren

var nums = new[]{1,2,3,4};
var sum = nums.Aggregate( (a,b) => a + b);
Console.WriteLine(sum); // output: 10 (1+2+3+4)

Dies fügt hinzu 1und 2zu machen 3. Dann werden 3(Ergebnis des vorherigen) und 3(nächstes Element in Folge) hinzugefügt, um zu machen 6. Dann fügt hinzu 6und 4zu machen 10.

Beispiel 2. Erstellen Sie eine CSV aus einem Array von Zeichenfolgen

var chars = new []{"a","b","c", "d"};
var csv = chars.Aggregate( (a,b) => a + ',' + b);
Console.WriteLine(csv); // Output a,b,c,d

Dies funktioniert ähnlich. Verketten Sie aein Komma und bmachen Sie a,b. Dann a,b mit einem Komma verketten und cmachen a,b,c. und so weiter.

Beispiel 3. Multiplizieren von Zahlen mit einem Startwert

Der Vollständigkeit halber ist es eine Überlast von Aggregatedem einen Ausgangswert annimmt.

var multipliers = new []{10,20,30,40};
var multiplied = multipliers.Aggregate(5, (a,b) => a * b);
Console.WriteLine(multiplied); //Output 1200000 ((((5*10)*20)*30)*40)

Ähnlich wie in den obigen Beispielen beginnt dies mit einem Wert von 5und multipliziert ihn mit dem ersten Element der Sequenz 10, das ein Ergebnis von ergibt 50. Dieses Ergebnis wird übertragen und mit der nächsten Zahl in der Sequenz multipliziert 20, um ein Ergebnis von zu erhalten 1000. Dies setzt sich durch die verbleibenden 2 Elemente der Sequenz fort.

Live-Beispiele: http://rextester.com/ZXZ64749
Dokumente: http://msdn.microsoft.com/en-us/library/bb548651.aspx


Nachtrag

In Beispiel 2 oben wird die Verkettung von Zeichenfolgen verwendet, um eine durch Komma getrennte Liste von Werten zu erstellen. Dies ist eine vereinfachte Methode, um die Verwendung Aggregatedieser Antwort zu erklären . Wenn Sie diese Technik jedoch verwenden, um tatsächlich eine große Menge von durch Kommas getrennten Daten zu erstellen, ist es besser, a zu verwenden StringBuilder, und dies ist vollständig kompatibel mit der AggregateVerwendung der gesetzten Überladung, um die zu initiieren StringBuilder.

var chars = new []{"a","b","c", "d"};
var csv = chars.Aggregate(new StringBuilder(), (a,b) => {
    if(a.Length>0)
        a.Append(",");
    a.Append(b);
    return a;
});
Console.WriteLine(csv);

Aktualisiertes Beispiel: http://rextester.com/YZCVXV6464

Jamiec
quelle
11
Eine weitere Erklärung für die Erstbeschreibung ist, dass die von Ihnen bereitgestellte Funktion immer die ersten beiden Elemente kombiniert, bis das Array auf ein Element verkleinert wird. So [1,2,3,4]wird es [3,3,4]dann [6,4]und endlich sein [10]. Anstatt ein Array mit einem einzelnen Wert zurückzugeben, erhalten Sie nur den Wert selbst.
David Raab
2
Kann ich eine Aggregatfunktion vorzeitig beenden? Zum Beispiel chars.Aggregate ((a, b) => {if (a == 'a') bricht das gesamte Aggregat, sonst gibt a + ',' + b} zurück)
Jeff Tian
13
@ JeffTian - Ich würde vorschlagen, eine zu verketten und TakeWhiledann Aggregate- das ist die Pflicht von Enumerable-Erweiterungen - sie sind leicht verkettbar. So enden Sie mit TakeWhile(a => a == 'a').Aggregate(....). Siehe dieses Beispiel: rextester.com/WPRA60543
Jamiec
2
Als Nebenbemerkung zum Nachtrag könnte der gesamte Block leicht durch ersetzt werden var csv = string.Join(",", chars)(kein Aggregat oder Stringbuilder erforderlich) - aber ja, ich weiß, der Sinn der Antwort bestand darin, eine beispielhafte Verwendung des Aggregats anzugeben, damit es cool ist. Aber ich wollte immer noch erwähnen, dass es nicht empfohlen wird, nur Strings zu verbinden, dafür gibt es bereits eine Methode ...
T_D
2
Eine andere übliche Verwendung (bisher die einzige, die ich überhaupt im Produktionscode gesehen habe) ist das Erhalten von minimalen oder maximalen Artikeln wievar biggestAccount = Accounts.Aggregate((a1, a2) => a1.Amount >= a2.Amount ? a1 : a2);
Franck
133

Es hängt teilweise davon ab, von welcher Überlastung Sie sprechen, aber die Grundidee ist:

  • Beginnen Sie mit einem Startwert als "aktuellem Wert"
  • Durchlaufen Sie die Sequenz. Für jeden Wert in der Sequenz:
    • Wenden Sie eine benutzerdefinierte Funktion an, (currentValue, sequenceValue)in die transformiert werden soll(nextValue)
    • einstellen currentValue = nextValue
  • Gib das Finale zurück currentValue

Sie können den AggregateBeitrag in meiner Edulinq-Reihe nützlich finden - er enthält eine detailliertere Beschreibung (einschließlich der verschiedenen Überladungen) und Implementierungen.

Ein einfaches Beispiel ist die Verwendung Aggregateals Alternative zu Count:

// 0 is the seed, and for each item, we effectively increment the current value.
// In this case we can ignore "item" itself.
int count = sequence.Aggregate(0, (current, item) => current + 1);

Oder vielleicht alle Längen von Strings in einer Folge von Strings summieren:

int total = sequence.Aggregate(0, (current, item) => current + item.Length);

Persönlich finde ich das seltenAggregate nützlich - die "maßgeschneiderten" Aggregationsmethoden sind normalerweise gut genug für mich.

Jon Skeet
quelle
6
@Jon Gibt es asynchrone Variationen von Aggregate, die die Elemente in einen Baum aufteilen, damit die Arbeit zwischen den Kernen aufgeteilt werden kann? Es scheint, dass das Design der Methode mit den Konzepten "Reduzieren" oder "Falten" übereinstimmt, aber ich weiß nicht, ob dies wirklich unter der Haube geschieht oder einfach die Liste der Elemente durchläuft.
AaronLS
@ Jon: Der oben erwähnte Edulink funktioniert nicht. Kannst du mich zum richtigen Link weiterleiten? Und können Sie bitte genauer auf den Begriff "maßgeschneiderte" Aggregationsfunktionen eingehen, den Sie in Ihrer Antwort verwendet haben?
Koushik
1
@Koushik: Ich habe den Link in der Post behoben. Mit "maßgeschneiderten" Aggregationsfunktionen meine ich Dinge wie Max / Min / Count / Sum.
Jon Skeet
62

Superkurzes Aggregat funktioniert wie Fold in Haskell / ML / F #.

Etwas länger .Max (), .Min (), .Sum (), .Average () durchlaufen alle Elemente in einer Sequenz und aggregieren sie mit der jeweiligen Aggregatfunktion. .Aggregate () ist ein verallgemeinerter Aggregator, der es dem Entwickler ermöglicht, den Startstatus (auch bekannt als Seed) und die Aggregatfunktion anzugeben.

Ich weiß, dass Sie um eine kurze Erklärung gebeten haben, aber ich dachte, als andere ein paar kurze Antworten gaben, dachte ich, dass Sie vielleicht an einer etwas längeren interessiert sein würden

Lange Version mit Code Eine Möglichkeit, um zu veranschaulichen, was dies bedeutet, besteht darin, zu zeigen, wie Sie die Beispielstandardabweichung einmal mit foreach und einmal mit .Aggregate implementieren. Hinweis: Ich habe die Leistung hier nicht priorisiert, daher iteriere ich unnötig mehrmals über die Sammlung

Zuerst eine Hilfsfunktion, mit der eine Summe quadratischer Abstände erstellt wird:

static double SumOfQuadraticDistance (double average, int value, double state)
{
    var diff = (value - average);
    return state + diff * diff;
}

Dann probieren Sie die Standardabweichung mit ForEach:

static double SampleStandardDeviation_ForEach (
    this IEnumerable<int> ints)
{
    var length = ints.Count ();
    if (length < 2)
    {
        return 0.0;
    }

    const double seed = 0.0;
    var average = ints.Average ();

    var state = seed;
    foreach (var value in ints)
    {
        state = SumOfQuadraticDistance (average, value, state);
    }
    var sumOfQuadraticDistance = state;

    return Math.Sqrt (sumOfQuadraticDistance / (length - 1));
}

Dann einmal mit .Aggregate:

static double SampleStandardDeviation_Aggregate (
    this IEnumerable<int> ints)
{
    var length = ints.Count ();
    if (length < 2)
    {
        return 0.0;
    }

    const double seed = 0.0;
    var average = ints.Average ();

    var sumOfQuadraticDistance = ints
        .Aggregate (
            seed,
            (state, value) => SumOfQuadraticDistance (average, value, state)
            );

    return Math.Sqrt (sumOfQuadraticDistance / (length - 1));
}

Beachten Sie, dass diese Funktionen identisch sind, außer wie sumOfQuadraticDistance berechnet wird:

var state = seed;
foreach (var value in ints)
{
    state = SumOfQuadraticDistance (average, value, state);
}
var sumOfQuadraticDistance = state;

Gegen:

var sumOfQuadraticDistance = ints
    .Aggregate (
        seed,
        (state, value) => SumOfQuadraticDistance (average, value, state)
        );

Was .Aggregate also tut, ist, dass es dieses Aggregatormuster kapselt, und ich gehe davon aus, dass die Implementierung von .Aggregate ungefähr so ​​aussehen würde:

public static TAggregate Aggregate<TAggregate, TValue> (
    this IEnumerable<TValue> values,
    TAggregate seed,
    Func<TAggregate, TValue, TAggregate> aggregator
    )
{
    var state = seed;

    foreach (var value in values)
    {
        state = aggregator (state, value);
    }

    return state;
}

Die Verwendung der Standardabweichungsfunktionen würde ungefähr so ​​aussehen:

var ints = new[] {3, 1, 4, 1, 5, 9, 2, 6, 5, 4};
var average = ints.Average ();
var sampleStandardDeviation = ints.SampleStandardDeviation_Aggregate ();
var sampleStandardDeviation2 = ints.SampleStandardDeviation_ForEach ();

Console.WriteLine (average);
Console.WriteLine (sampleStandardDeviation);
Console.WriteLine (sampleStandardDeviation2);

meiner bescheidenen Meinung nach

Hilft .Aggregate also bei der Lesbarkeit? Im Allgemeinen liebe ich LINQ, weil ich denke, dass .Where, .Select, .OrderBy usw. die Lesbarkeit erheblich verbessern (wenn Sie inlinierte hierarhische .Selects vermeiden). Aggregate muss aus Gründen der Vollständigkeit in Linq sein, aber ich persönlich bin nicht so überzeugt, dass .Aggregate die Lesbarkeit im Vergleich zu einem gut geschriebenen Foreach erhöht.

Nur ein weiterer Metaprogrammer
quelle
+1 Ausgezeichnet! Aber Erweiterungsmethoden SampleStandardDeviation_Aggregate()und SampleStandardDeviation_ForEach()können nicht sein private(standardmäßig in Abwesenheit eines Zugriffsqualifizierers), sollten also entweder publicoder internal, wie mir scheint
Fulproof
Zu Ihrer Information: Wenn ich mich richtig erinnere, waren die Erweiterungsmethoden in meinem Beispiel Teil derselben Klasse, in der sie verwendet wurden ==> private Arbeiten in diesem Fall.
Nur ein weiterer Metaprogrammer
39

Ein Bild sagt mehr als tausend Worte

Erinnerung:
Func<X, Y, R>ist eine Funktion mit zwei Eingaben vom Typ Xund Y, die ein Ergebnis vom Typ zurückgibt R.

Enumerable.Aggregate hat drei Überladungen:


Überladung 1:

A Aggregate<A>(IEnumerable<A> a, Func<A, A, A> f)

Aggregat1

Beispiel:

new[]{1,2,3,4}.Aggregate((x, y) => x + y);  // 10


Diese Überlastung ist einfach, weist jedoch die folgenden Einschränkungen auf:

  • Die Sequenz muss mindestens ein Element enthalten,
    sonst löst die Funktion ein InvalidOperationException.
  • Elemente und Ergebnis müssen vom gleichen Typ sein.



Überladung 2:

B Aggregate<A, B>(IEnumerable<A> a, B bIn, Func<B, A, B> f)

Aggregate2

Beispiel:

var hayStack = new[] {"straw", "needle", "straw", "straw", "needle"};
var nNeedles = hayStack.Aggregate(0, (n, e) => e == "needle" ? n+1 : n);  // 2


Diese Überlastung ist allgemeiner:

  • Es muss ein Startwert angegeben werden ( bIn).
  • Die Sammlung kann leer sein.
    In diesem Fall liefert die Funktion als Ergebnis den Startwert.
  • Elemente und Ergebnisse können unterschiedliche Typen haben.



Überladung 3:

C Aggregate<A,B,C>(IEnumerable<A> a, B bIn, Func<B,A,B> f, Func<B,C> f2)


Die dritte Überlastung ist IMO nicht sehr nützlich.
Dasselbe kann prägnanter geschrieben werden, indem Überladung 2 gefolgt von einer Funktion verwendet wird, die das Ergebnis transformiert.


Die Illustrationen stammen aus diesem ausgezeichneten Blogpost .

3dGrabber
quelle
Dies wäre eine großartige Antwort ... auf eine Frage zu Haskel. Aber es gibt keine Überlastung von Aggegatein .net, die eine benötigt Func<T, T, T>.
Jamiec
4
Ja, das gibt es . Sie verwenden es in Ihrer eigenen Antwort!
3dGrabber
1
Upvoting, weil Sie sorgfältig beschreiben, was passiert, wenn die Sequenz leer ist. Sei N die Anzahl der Elemente in der Quelle. Wir beobachten, dass die Überlastung, die kein a benötigt seed, die Akkumulatorfunktion N -1 mal anwendet ; während die anderen Überlastungen (das sich ein Take seed) gelten die Akkumulatorfunktion N mal.
Jeppe Stig Nielsen
17

Aggregat wird grundsätzlich zum Gruppieren oder Zusammenfassen von Daten verwendet.

Laut MSDN "Aggregatfunktion Wendet eine Akkumulatorfunktion über eine Sequenz an."

Beispiel 1: Fügen Sie alle Zahlen in einem Array hinzu.

int[] numbers = new int[] { 1,2,3,4,5 };
int aggregatedValue = numbers.Aggregate((total, nextValue) => total + nextValue);

* wichtig: Der anfängliche Aggregatwert ist standardmäßig das 1-Element in der Erfassungssequenz. dh: Der Anfangswert der Gesamtvariablen ist standardmäßig 1.

variable Erklärung

total: Es enthält den von der Funktion zurückgegebenen Summenwert (aggregierter Wert).

nextValue: Dies ist der nächste Wert in der Array-Sequenz. Dieser Wert wird dann zum aggregierten Wert addiert, dh insgesamt.

Beispiel 2: Fügen Sie alle Elemente in einem Array hinzu. Stellen Sie außerdem den anfänglichen Akkumulatorwert so ein, dass ab 10 mit dem Hinzufügen begonnen wird.

int[] numbers = new int[] { 1,2,3,4,5 };
int aggregatedValue = numbers.Aggregate(10, (total, nextValue) => total + nextValue);

Argumente Erklärung:

Das erste Argument ist der Anfangsbuchstabe (Startwert, dh Startwert), mit dem die Addition mit dem nächsten Wert im Array gestartet wird.

Das zweite Argument ist eine Funktion, die 2 int benötigt.

1.total: Dies gilt genauso wie vor dem Summenwert (aggregierter Wert), der von der Funktion nach der Berechnung zurückgegeben wird.

2.nextValue :: Dies ist der nächste Wert in der Array-Sequenz. Dieser Wert wird dann zum aggregierten Wert addiert, dh insgesamt.

Wenn Sie diesen Code auch debuggen, erhalten Sie ein besseres Verständnis für die Funktionsweise von Aggregaten.

maxspan
quelle
7

Ich habe viel aus Jamiecs Antwort gelernt .

Wenn Sie nur eine CSV-Zeichenfolge generieren müssen, können Sie dies versuchen.

var csv3 = string.Join(",",chars);

Hier ist ein Test mit 1 Million Zeichenfolgen

0.28 seconds = Aggregate w/ String Builder 
0.30 seconds = String.Join 

Der Quellcode ist hier

Rm558
quelle
Wenn ich in dotnetfiddle.net denselben Code wie im Link angegeben ausführte , wurde für "string.Join" "Schwerwiegender Fehler: Speicherbelegungslimit wurde überschritten" angezeigt, aber Aggregate funktionierte immer wie erwartet. Daher glaube ich, dass dies nicht empfohlen wird, um String.Join
Manish Jain
Seltsam? Als ich die erste Stoppuhr kommentierte, die für Aggregate war; dann erhalte ich keinen "Schwerwiegender Fehler: Speicherbelegungslimit wurde überschritten". Bitte erkläre! Link: dotnetfiddle.net/6YyumS
Manish Jain
dotnetfiddle.net hat ein Speicherlimit, wenn der Ausführungsstopp erreicht ist. Wenn Sie den Aggregatcode vor den String.Join-Code verschieben, wird möglicherweise ein Fehler für das Aggregat angezeigt.
Rm558
7

Zusätzlich zu all den tollen Antworten hier habe ich es auch verwendet, um einen Gegenstand durch eine Reihe von Transformationsschritten zu führen.

Wenn eine Transformation als a implementiert ist Func<T,T>, können Sie a mehrere Transformationen hinzufügen List<Func<T,T>>und Aggregateeine Instanz von Tdurch jeden Schritt führen.

Ein konkreteres Beispiel

Sie möchten einen stringWert nehmen und ihn durch eine Reihe von Texttransformationen führen, die programmgesteuert erstellt werden können.

var transformationPipeLine = new List<Func<string, string>>();
transformationPipeLine.Add((input) => input.Trim());
transformationPipeLine.Add((input) => input.Substring(1));
transformationPipeLine.Add((input) => input.Substring(0, input.Length - 1));
transformationPipeLine.Add((input) => input.ToUpper());

var text = "    cat   ";
var output = transformationPipeLine.Aggregate(text, (input, transform)=> transform(input));
Console.WriteLine(output);

Dadurch wird eine Kette von Transformationen erstellt: Entfernen Sie führende und nachfolgende Leerzeichen -> entfernen Sie das erste Zeichen -> entfernen Sie das letzte Zeichen -> konvertieren Sie in Großbuchstaben. Schritte in dieser Kette können nach Bedarf hinzugefügt, entfernt oder neu angeordnet werden, um die erforderliche Transformationspipeline zu erstellen.

Das Endergebnis dieser speziellen Pipeline, ist , dass " cat "wird "A".


Dies kann sehr mächtig werden, sobald Sie erkennen, dass Tdies alles sein kann . Dies könnte für Bildtransformationen wie Filter am BitMapBeispiel verwendet werden.

Bradley Uffner
quelle
4

Definition

Die Aggregatmethode ist eine Erweiterungsmethode für generische Sammlungen. Die Aggregatmethode wendet eine Funktion auf jedes Element einer Sammlung an. Wendet nicht nur eine Funktion an, sondern nimmt ihr Ergebnis als Anfangswert für die nächste Iteration. Als Ergebnis erhalten wir einen berechneten Wert (min, max, avg oder einen anderen statistischen Wert) aus einer Sammlung.

Daher ist die Aggregatmethode eine Form der sicheren Implementierung einer rekursiven Funktion.

Sicher , da die Rekursion über jedes Element einer Sammlung iteriert und wir durch eine falsche Ausgangsbedingung keine Endlosschleifenaufhängung erhalten können. Rekursiv , da das Ergebnis der aktuellen Funktion als Parameter für den nächsten Funktionsaufruf verwendet wird.

Syntax:

collection.Aggregate(seed, func, resultSelector);
  • Samen - Anfangswert der Standardeinstellung;
  • func - unsere rekursive Funktion. Es kann ein Lambda-Ausdruck, ein Func-Delegat oder ein Funktionstyp TF sein (T-Ergebnis, T nextValue);
  • resultSelector - Dies kann eine Funktion wie func oder ein Ausdruck zum Berechnen, Transformieren, Ändern und Konvertieren des Endergebnisses sein.

Wie es funktioniert:

var nums = new[]{1, 2};
var result = nums.Aggregate(1, (result, n) => result + n); //result = (1 + 1) + 2 = 4
var result2 = nums.Aggregate(0, (result, n) => result + n, response => (decimal)response/2.0); //result2 = ((0 + 1) + 2)*1.0/2.0 = 3*1.0/2.0 = 3.0/2.0 = 1.5

Praktische Anwendung:

  1. Finden Sie Factorial aus einer Zahl n:

int n = 7;
var numbers = Enumerable.Range(1, n);
var factorial = numbers.Aggregate((result, x) => result * x);

das macht das gleiche wie diese Funktion:

public static int Factorial(int n)
{
   if (n < 1) return 1;

   return n * Factorial(n - 1);
}
  1. Aggregate () ist eine der leistungsstärksten LINQ-Erweiterungsmethoden wie Select () und Where (). Wir können es verwenden, um die Summe (), Min () zu ersetzen. Max (), Avg () -Funktionalität oder zum Ändern durch Implementieren des Additionskontexts:
    var numbers = new[]{3, 2, 6, 4, 9, 5, 7};
    var avg = numbers.Aggregate(0.0, (result, x) => result + x, response => (double)response/(double)numbers.Count());
    var min = numbers.Aggregate((result, x) => (result < x)? result: x);
  1. Komplexere Verwendung von Erweiterungsmethoden:
    var path = @“c:\path-to-folder”;

    string[] txtFiles = Directory.GetFiles(path).Where(f => f.EndsWith(“.txt”)).ToArray<string>();
    var output = txtFiles.Select(f => File.ReadAllText(f, Encoding.Default)).Aggregate<string>((result, content) => result + content);

    File.WriteAllText(path + summary.txt”, output, Encoding.Default);

    Console.WriteLine(“Text files merged into: {0}”, output); //or other log info
YuriUn
quelle
Ziemlich gute erste Antwort. Gut gemacht! Schade, dass es so eine alte Frage ist, sonst hättest du viele positive
Stimmen
1

Dies ist eine Erklärung zur Verwendung Aggregatein einer Fluent-API wie Linq Sorting.

var list = new List<Student>();
var sorted = list
    .OrderBy(s => s.LastName)
    .ThenBy(s => s.FirstName)
    .ThenBy(s => s.Age)
    .ThenBy(s => s.Grading)
    .ThenBy(s => s.TotalCourses);

und lassen Sie uns sehen, dass wir eine Sortierfunktion implementieren möchten, die eine Reihe von Feldern verwendet. Dies ist sehr einfach Aggregateanstelle einer for-Schleife wie folgt :

public static IOrderedEnumerable<Student> MySort(
    this List<Student> list,
    params Func<Student, object>[] fields)
{
    var firstField = fields.First();
    var otherFields = fields.Skip(1);

    var init = list.OrderBy(firstField);
    return otherFields.Skip(1).Aggregate(init, (resultList, current) => resultList.ThenBy(current));
}

Und wir können es so verwenden:

var sorted = list.MySort(
    s => s.LastName,
    s => s.FirstName,
    s => s.Age,
    s => s.Grading,
    s => s.TotalCourses);
Jaider
quelle
1

Jeder hat seine Erklärung gegeben. Meine Erklärung ist so.

Die Aggregatmethode wendet eine Funktion auf jedes Element einer Sammlung an. Nehmen wir zum Beispiel die Sammlung {6, 2, 8, 3} und die Funktion Add (Operator +), die sie ausführt (((6 + 2) +8) +3) und gibt 19 zurück

var numbers = new List<int> { 6, 2, 8, 3 };
int sum = numbers.Aggregate(func: (result, item) => result + item);
// sum: (((6+2)+8)+3) = 19

In diesem Beispiel wird anstelle des Lambda-Ausdrucks die benannte Methode Add übergeben.

var numbers = new List<int> { 6, 2, 8, 3 };
int sum = numbers.Aggregate(func: Add);
// sum: (((6+2)+8)+3) = 19

private static int Add(int x, int y) { return x + y; }
bizimunda
quelle
0

Eine kurze und wesentliche Definition könnte folgende sein: Die Linq Aggregate-Erweiterungsmethode ermöglicht es, eine Art rekursive Funktion zu deklarieren, die auf die Elemente einer Liste angewendet wird, deren Operanden zwei sind: die Elemente in der Reihenfolge, in der sie in der Liste vorhanden sind, jeweils ein Element und das Ergebnis der vorherigen rekursiven Iteration oder nichts, wenn noch keine Rekursion.

Auf diese Weise können Sie die Fakultät für Zahlen berechnen oder Zeichenfolgen verketten.

Ciro Corvino
quelle
0

Aggregat zum Summieren von Spalten in einem mehrdimensionalen Ganzzahlarray

        int[][] nonMagicSquare =
        {
            new int[] {  3,  1,  7,  8 },
            new int[] {  2,  4, 16,  5 },
            new int[] { 11,  6, 12, 15 },
            new int[] {  9, 13, 10, 14 }
        };

        IEnumerable<int> rowSums = nonMagicSquare
            .Select(row => row.Sum());
        IEnumerable<int> colSums = nonMagicSquare
            .Aggregate(
                (priorSums, currentRow) =>
                    priorSums.Select((priorSum, index) => priorSum + currentRow[index]).ToArray()
                );

Mit Index auswählen wird in der Aggregatfunktion verwendet, um die übereinstimmenden Spalten zu summieren und ein neues Array zurückzugeben. {3 + 2 = 5, 1 + 4 = 5, 7 + 16 = 23, 8 + 5 = 13}.

        Console.WriteLine("rowSums: " + string.Join(", ", rowSums)); // rowSums: 19, 27, 44, 46
        Console.WriteLine("colSums: " + string.Join(", ", colSums)); // colSums: 25, 24, 45, 42

Das Zählen der Anzahl von Wahrheiten in einem Booleschen Array ist jedoch schwieriger, da sich der akkumulierte Typ (int) vom Quelltyp (bool) unterscheidet. hier ist ein Samen notwendig, um die zweite Überladung zu nutzen.

        bool[][] booleanTable =
        {
            new bool[] { true, true, true, false },
            new bool[] { false, false, false, true },
            new bool[] { true, false, false, true },
            new bool[] { true, true, false, false }
        };

        IEnumerable<int> rowCounts = booleanTable
            .Select(row => row.Select(value => value ? 1 : 0).Sum());
        IEnumerable<int> seed = new int[booleanTable.First().Length];
        IEnumerable<int> colCounts = booleanTable
            .Aggregate(seed,
                (priorSums, currentRow) =>
                    priorSums.Select((priorSum, index) => priorSum + (currentRow[index] ? 1 : 0)).ToArray()
                );

        Console.WriteLine("rowCounts: " + string.Join(", ", rowCounts)); // rowCounts: 3, 1, 2, 2
        Console.WriteLine("colCounts: " + string.Join(", ", colCounts)); // colCounts: 3, 2, 1, 2
Dan M.
quelle