2009-10-02 13 views
23

que j'ai vu l'exemple simple de la fonction .net globale de travail comme ceci:Linq Aggregate types complexes dans une chaîne

string[] words = { "one", "two", "three" }; 
var res = words.Aggregate((current, next) => current + ", " + next); 
Console.WriteLine(res); 

Comment la fonction « globale » pourrait être utilisé si vous souhaitez agréger plus complexe les types? Par exemple: une classe avec 2 propriétés telles que « clé » et « valeur » et que vous voulez la sortie comme ceci:

"MyAge: 33, MyHeight: 1.75, MyWeight:90" 

Répondre

40

Vous avez deux options:

  1. projet à un string et total:

    var values = new[] { 
        new { Key = "MyAge", Value = 33.0 }, 
        new { Key = "MyHeight", Value = 1.75 }, 
        new { Key = "MyWeight", Value = 90.0 } 
    }; 
    var res1 = values.Select(x => string.Format("{0}:{1}", x.Key, x.Value)) 
           .Aggregate((current, next) => current + ", " + next); 
    Console.WriteLine(res1); 
    

    Cela a l'avantage d'utiliser le premier élément string comme la graine (pas ajouté ","), mais consommera plus de mémoire pour les chaînes créées dans le processus.

  2. Utilisez une surcharge globale qui accepte une graine, peut-être un StringBuilder:

    var res2 = values.Aggregate(new StringBuilder(), 
        (current, next) => current.AppendFormat(", {0}:{1}", next.Key, next.Value), 
        sb => sb.Length > 2 ? sb.Remove(0, 2).ToString() : ""); 
    Console.WriteLine(res2); 
    

    Le second délégué convertit notre StringBuilder en string, utilisant le conditionnel à couper le départ « ».

+0

Parfait, juste ce que je cherchais, afin que je puisse les chronométrer tous, à partir de mes horaires, rouler le vôtre pour la boucle était plus rapide (j'ai seulement 1 ou 2 articles dans mon test) – Myster

+0

Avec si peu d'éléments dans la liste , le succès de la mise en place des énumérateurs "supplémentaires" pour Select/Aggregate semblera plutôt sévère comparé à une solution plus impérative. Comme pour la plupart des solutions fonctionnelles, la question est de savoir si le compromis performance/lisibilité est acceptable. Étant donné que l'agrégat non familier serait pour la plupart des gens, il serait facile de conclure que dans ce cas, la solution impérative est «mieux» indépendante de la performance. – dahlbyk

+0

Après l'avoir écrit dans les deux sens, je suis d'accord. L'agrégat est assez cryptique, mais c'est un bon outil à avoir dans ma boîte ;-) – Myster

3

La fonction globale accepte un paramètre de délégué. Vous définissez le comportement souhaité en modifiant le délégué.

var res = data.Aggregate((current, next) => current + ", " + next.Key + ": " + next.Value); 
+6

Si vous regroupez dans un type autre que la source, vous devez spécifier une graine. Spécifier "" comme une graine compilerait, mais le résultat commencera par ",". – dahlbyk

4

agrégat a 3 surcharges, de sorte que vous pouvez utiliser celui qui a différents types d'accumuler les éléments que vous énumérez.

Vous devez transmettre une valeur initiale (votre classe personnalisée) et une méthode à ajouter pour fusionner la graine avec une valeur. Exemple:

MyObj[] vals = new [] { new MyObj(1,100), new MyObj(2,200), ... }; 
MySum result = vals.Aggregate<MyObj, MySum>(new MySum(), 
    (sum, val) => 
    { 
     sum.Sum1 += val.V1; 
     sum.Sum2 += val.V2; 
     return sum; 
    } 
Questions connexes