Aggregate

Fonction d'accumulation sur une séquence

12/08/2011 1 474 lectures Sébastien Sougnez

La structure interne ainsi que le design d'AreaProg ont récemment été modifiés.
Suite à cela, le format de certains articles a été perturbé. Le problème est connu et en cours de résolution. Merci de votre compréhension.

La fonction « Aggregate » est plus une fonction de transformation/accumulation que de récupération d’élément. En effet, elle permet de parcourir tous les éléments d’une liste d’objets et d’exécuter un « pattern » d’accumulation. « Aggregate » est une fonction « non différée », elle renvoie donc immédiatement la valeur (elle n’utilise pas « yield »).

Aggregate<TSource>(IEnumerable<TSource>, Func<TSource, TSource, TSource>)

La première forme de cette méthode attend en paramètre un « Func » qui permettra de définir l’accumulation appliquée aux différents éléments de la collection. Imaginons par exemple l’application console suivante :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Aggregate
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> words = new List<string> { 
                "L'escalier", "de", "la", "science", "est", 
                "l'échelle", "de", "Jacob,", "il", "ne", 
                "s'achève", "qu'aux", "pieds", "de", "Dieu." 
            };

            Console.WriteLine(FirstAggregate(words));
            Console.ReadLine();
        }

        private static string FirstAggregate(IEnumerable<string> values)
        {
            return values.Aggregate((s1, s2) => s1 + " " + s2);
        }
    }
}
Nous possédons une liste de mots que nous allons assembler en une seule et même phrase. Pour cela, il suffit de parcourir toute la collection et d’assembler chaque mot les uns aux autres. C’est à ça que sert la fonction « Aggregate ». Le principe de cette fonction est de stocker dans une variable temporaire le résultat de chaque exécution du « Func » passé en paramètre. Avant d’aller plus loin dans ces explications, voyons le code de cette fonction (récupéré via « Reflector ») :
public static TSource Aggregate<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func)
{
    if (source == null)
    {
        throw Error.ArgumentNull("source");
    }
    if (func == null)
    {
        throw Error.ArgumentNull("func");
    }
    using (IEnumerator<TSource> enumerator = source.GetEnumerator())
    {
        if (!enumerator.MoveNext())
        {
            throw Error.NoElements();
        }
        TSource current = enumerator.Current;
        while (enumerator.MoveNext())
        {
            current = func(current, enumerator.Current);
        }
        return current;
    }
}
Une fois les différentes vérifications effectuées (paramètres différents de « null »), cette fonction va créer un objet de type « TSource », nommé « current » et initialiser sa valeur sur « enumerator.Current », c’est-à-dire, la première valeur de la collection, donc ici « L’escalier ». Nous entrons ensuite dans une boucle qui va à chaque fois placer dans la variable « current » le résultat renvoyé par le « Func » passé en paramètre auquel nous passons la variable « current » et la valeur actuelle de l’énumération. Lors du premier passage, il va donc exécuter le « Func » avec comme paramètre « L’escalier » (valeur de « current ») et « de » (valeur courante de l’énumération). Notre « Func » faisant une simple concaténation va donc renvoyer « L’escalier de » qui sera placé dans « current ». De la même manière, toute la collection va être parcourue et la variable « current » va sans arrêt contenir la concaténation des différents mots jusqu’à ce que la boucle « while » soit terminée. Le résultat renvoyé par notre application sera donc :
Image

Aggregate<TSource, TAccumulate>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>)

Cette forme de la fonction « Aggregate » n’est pas beaucoup plus compliquée que la précédente. Cette fois, nous avons la possibilité d’instancier nous-même la valeur de la variable temporaire qui contiendra le résultat de l’accumulation. Modifiez donc l’application précédente en ajoutant cette fonction :
private static string SecondAggregate(IEnumerable<string> values)
{
    return values.Aggregate("La phrase est: ", (s1, s2) => s1 + " " + s2);
}
Et appelez cette méthode dans la fonction « main » de cette manière :
Console.WriteLine(SecondAggregate(words));
Cette fois, le résultat affiché sera :
Image
Comme vous le voyez, cette fois, le résultat est précédé de « La phrase est : ».

Aggregate<TSource, TAccumulate, TResult>(IEnumerable<TSource>, TAccumulate, Func<TAccumulate, TSource, TAccumulate>, Func<TAccumulate, TResult>)

Il existe également une surcharge de la fonction « Aggregate » permettant d’appliquer une fonction sur le résultat renvoyé par la fonction. Personnellement, j’utilise toujours cette forme pour une bonne version. Généralement, nous utilisons cette fonction pour récupérer une chaîne de caractères résultant de l’accumulation d’autres chaines de caractères ou d’objets. Vous n’êtes certainement pas sans savoir que lorsque nous devons faire beaucoup d’opérations sur une chaîne de caractères, il est plus efficace de le faire sur un « StringBuilder » plutôt que sur un « string ». Il est donc possible de faire cela et de renvoyer quand même un « string » de cette manière :
private static string ThirdAggregate(IEnumerable<string> values)
{
    return values.Aggregate(new StringBuilder("La phrase est: "), (s1, s2) => s1.AppendFormat(" {0}", s2), s => s.ToString());
}
Appelez cette fonction dans votre « main » comme ceci :
Console.WriteLine(ThirdAggregate(words));
Nous créons donc un « StringBuilder » qui contiendra l’accumulation des mots contenus dans la liste sur laquelle la fonction est appelée et enfin, nous renvoyons le résultat de la méthode « ToString » appliquée sur ce « StringBuilder ». Télécharger

Noter

Veuillez vous identifier ou vous inscrire pour donner une note à cet article.

Commentaires / Questions

Aucun commentaire.

Veuillez vous identifier ou vous inscrire pour réagir à cet article.

Avatar

Sébastien Sougnez

Envoyer un mail Site web Windows live messenger LinkedIn Twitter Facebook MVP Administrateur

0 point