856 votes

LINQ Agrégat algorithme expliqué

Cela peut sembler nul, mais je n'ai pas pu trouver une bonne explication de Aggregate.

Bonne signifie courte, descriptive, complète avec un petit exemple clair.

11voto

Bradley Uffner Points 12947

En plus de toutes les excellentes réponses déjà présentes ici, je l'ai aussi utilisé pour faire passer un élément à travers une série d'étapes de transformation.

Si une transformation est implémentée en tant que Func, vous pouvez ajouter plusieurs transformations à une List> et utiliser Aggregate pour faire passer une instance de T à travers chaque étape.

Un exemple plus concret

Vous voulez prendre une valeur string, et la faire passer à travers une série de transformations de texte qui pourraient être construites de manière programmatique.

var transformationPipeLine = new List>();
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 = "    chat   ";
var output = transformationPipeLine.Aggregate(text, (input, transform)=> transform(input));
Console.WriteLine(output);

Cela créera une chaîne de transformations : Supprimer les espaces en début et en fin -> supprimer le premier caractère -> supprimer le dernier caractère -> convertir en majuscules. Les étapes de cette chaîne peuvent être ajoutées, supprimées ou réorganisées au besoin, pour créer le type de pipeline de transformation nécessaire.

Le résultat final de ce pipeline spécifique est que " chat " devient "A".


Ceci peut devenir très puissant une fois que vous réalisez que T peut être quelque chose. Cela pourrait être utilisé pour des transformations d'image, comme des filtres, en utilisant BitMap comme exemple;

7voto

Rm558 Points 1286

J'ai beaucoup appris de la réponse de Jamiec.

Si le seul besoin est de générer une chaîne CSV, vous pouvez essayer ceci.

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

Voici un test avec 1 million de chaînes

0,28 secondes = Agrégation avec String Builder
0,30 secondes = String.Join

Le code source est disponible ici

7voto

YuriUn Points 51

Définition

La méthode d'agrégation est une méthode d'extension pour les collections génériques. La méthode d'agrégation applique une fonction à chaque élément d'une collection. Non seulement elle applique une fonction, mais elle utilise son résultat comme valeur initiale pour l'itération suivante. Ainsi, en résultat, nous obtiendrons une valeur calculée (min, max, moyenne, ou autre valeur statistique) à partir d'une collection.

Par conséquent, la méthode d'agrégation est une forme sûre d'implémentation d'une fonction récursive.

Sûre, car la récursion va itérer sur chaque élément d'une collection et nous ne pouvons pas obtenir de suspension de boucle infinie par une mauvaise condition de sortie. Réursive, car le résultat de la fonction actuelle est utilisé comme paramètre pour l'appel de fonction suivant.

Syntaxe :

collection.Aggregate(seed, func, resultSelector);
  • seed - valeur initiale par défaut;
  • func - notre fonction récursive. Elle peut être une expression lambda, un délégué Func ou une fonction de type T F(T result, T nextValue);
  • resultSelector - il peut s'agir d'une fonction comme func ou d'une expression pour calculer, transformer, changer, convertir le résultat final.

Comment ça fonctionne :

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

Utilisation pratique :

  1. Calculer le factoriel d'un nombre n :

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

ce qui fait la même chose que cette fonction :

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

   return n * Factorial(n - 1);
}
  1. Aggregate() est l'une des méthodes d'extension LINQ les plus puissantes, comme Select() et Where(). Nous pouvons l'utiliser pour remplacer les fonctionnalités Sum(), Min(). Max(), Avg(), ou pour les modifier en implémentant un contexte d'addition :

    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);
  2. Utilisation plus complexe des méthodes d'extension :

    var path = @“c:\chemin-vers-dossier”;
    
    string[] txtFiles = Directory.GetFiles(path).Where(f => f.EndsWith(“.txt”)).ToArray();
    var output = txtFiles.Select(f => File.ReadAllText(f, Encoding.Default)).Aggregate((result, content) => result + content);
    
    File.WriteAllText(path + “summary.txt”, output, Encoding.Default);
    
    Console.WriteLine(“Fichiers texte fusionnés en : {0}”, output); //ou autre info de journal

1voto

Jaider Points 2366

Ceci est une explication sur l'utilisation de Aggregate sur une API fluide telle que le tri Linq.

var liste = new List();
var trié = liste
    .OrderBy(s => s.LastName)
    .ThenBy(s => s.FirstName)
    .ThenBy(s => s.Age)
    .ThenBy(s => s.Grading)
    .ThenBy(s => s.TotalCourses);

et supposons que nous voulons implémenter une fonction de tri qui prend un ensemble de champs, c'est très facile en utilisant Aggregate au lieu d'une boucle for, comme ceci :

public static IOrderedEnumerable MonTri(
    this List liste,
    params Func[] champs)
{
    var premierChamp = champs.First();
    var autresChamps = champs.Skip(1);

    var init = liste.OrderBy(premierChamp);
    return autresChamps.Skip(1).Aggregate(init, (listeRésultat, actuel) => listeRésultat.ThenBy(actuel));
}

Et nous pouvons l'utiliser comme ceci :

var trié = liste.MonTri(
    s => s.LastName,
    s => s.FirstName,
    s => s.Age,
    s => s.Grading,
    s => s.TotalCourses);

1voto

Dan M Points 1

Aggregate utilisé pour additionner les colonnes dans un tableau d'entiers multidimensionnel

        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 rowSums = nonMagicSquare
            .Select(row => row.Sum());
        IEnumerable colSums = nonMagicSquare
            .Aggregate(
                (priorSums, currentRow) =>
                    priorSums.Select((priorSum, index) => priorSum + currentRow[index]).ToArray()
                );

La sélection avec un index est utilisée dans la fonction Aggregate pour additionner les colonnes correspondantes et retourner un nouveau tableau; { 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

Mais compter le nombre de vrais dans un tableau de booléens est plus difficile car le type accumulé (int) diffère du type source (bool); ici une graine est nécessaire afin d'utiliser le deuxième overload.

        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 rowCounts = booleanTable
            .Select(row => row.Select(value => value ? 1 : 0).Sum());
        IEnumerable seed = new int[booleanTable.First().Length];
        IEnumerable 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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X