Utiliser LINQ pour concaténer des chaînes

Quelle est la manière la plus efficace d’écrire la vieille école:

SsortingngBuilder sb = new SsortingngBuilder(); if (ssortingngs.Count > 0) { foreach (ssortingng s in ssortingngs) { sb.Append(s + ", "); } sb.Remove(sb.Length - 2, 2); } return sb.ToSsortingng(); 

… dans LINQ?

    Utilisez des requêtes agrégées comme celle-ci:

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

    Cela produit:

      un deux trois 

    Un agrégat est une fonction qui prend une collection de valeurs et renvoie une valeur scalaire. Les exemples de T-SQL incluent min, max et sum. VB et C # prennent tous deux en charge les agrégats. Les deux VB et C # supportent les agrégats comme méthodes d’extension. En utilisant la notation par points, on appelle simplement une méthode sur un object IEnumerable .

    Rappelez-vous que les requêtes agrégées sont exécutées immédiatement.

    http://msdn.microsoft.com/en-us/library/bb386914.aspx

    Comme cela n’utilise pas de SsortingngBuilder il aura des performances horribles pour les très longues séquences.

     return ssortingng.Join(", ", ssortingngs.ToArray()); 

    Dans .Net 4, il y a une nouvelle surcharge pour ssortingng.Join qui accepte IEnumerable . Le code ressemblerait alors à:

     return ssortingng.Join(", ", ssortingngs); 

    Pourquoi utiliser Linq?

     ssortingng[] s = {"foo", "bar", "baz"}; Console.WriteLine(Ssortingng.Join(", ", s)); 

    Cela fonctionne parfaitement et accepte tout IEnumerable pour autant que je m’en souvienne. Pas besoin d’ Aggregate tout ce qui est beaucoup plus lent.

    Avez-vous examiné la méthode d’extension Aggregate?

     var sa = (new[] { "yabba", "dabba", "doo" }).Aggregate((a,b) => a + "," + b); 

    Exemple concret de mon code:

     return selected.Select(query => query.Name).Aggregate((a, b) => a + ", " + b); 

    Une requête est un object qui possède une propriété Name qui est une chaîne et je souhaite les noms de toutes les requêtes sur la liste sélectionnée, séparés par des virgules.

    Vous pouvez utiliser SsortingngBuilder dans Aggregate :

      List ssortingngs = new List() { "one", "two", "three" }; SsortingngBuilder sb = ssortingngs .Select(s => s) .Aggregate(new SsortingngBuilder(), (ag, n) => ag.Append(n).Append(", ")); if (sb.Length > 0) { sb.Remove(sb.Length - 2, 2); } Console.WriteLine(sb.ToSsortingng()); 

    (The Select est là juste pour montrer que vous pouvez faire plus de choses LINQ.)

    Voici l’approche combinée Join / Linq sur laquelle j’ai opté après avoir examiné les autres réponses et les problèmes abordés dans une question similaire (à savoir que Aggregate et Concatenate échouent avec 0 éléments).

    ssortingng Result = Ssortingng.Join(",", split.Select(s => s.Name));

    ou (si s n’est pas une chaîne)

    ssortingng Result = Ssortingng.Join(",", split.Select(s => s.ToSsortingng()));

    • Simple
    • facile à lire et à comprendre
    • travaille pour des éléments génériques
    • permet d’utiliser des objects ou des propriétés d’object
    • gère le cas des éléments de longueur 0
    • pourrait être utilisé avec un filtrage Linq supplémentaire
    • fonctionne bien (du moins dans mon expérience)
    • ne nécessite pas la création (manuelle) d’un object supplémentaire (par exemple, SsortingngBuilder ) pour implémenter

    Et bien sûr, Join se charge de la virgule finale embêtante qui se glisse parfois dans d’autres approches ( for , foreach ), c’est pourquoi je cherchais en premier lieu une solution Linq.

    données de performances rapides pour le cas SsortingngBuilder vs Select & Aggregate sur 3000 éléments:

    Test unitaire – Durée (secondes)
    LINQ_SsortingngBuilder – 0.0036644
    LINQ_Select.Aggregate – 1.8012535

      [TestMethod()] public void LINQ_SsortingngBuilder() { IList ints = new List(); for (int i = 0; i < 3000;i++ ) { ints.Add(i); } StringBuilder idString = new StringBuilder(); foreach (int id in ints) { idString.Append(id + ", "); } } [TestMethod()] public void LINQ_SELECT() { IList ints = new List(); for (int i = 0; i < 3000; i++) { ints.Add(i); } string ids = ints.Select(query => query.ToSsortingng()) .Aggregate((a, b) => a + ", " + b); } 

    J’utilise toujours la méthode d’extension:

     public static ssortingng JoinAsSsortingng(this IEnumerable input, ssortingng seperator) { var ar = input.Select(i => i.ToSsortingng()).ToArray(); return ssortingng.Join(seperator, ar); } 

    Par «manière super cool LINQ », vous pourriez parler de la façon dont LINQ rend la functional programming beaucoup plus acceptable avec l’utilisation de méthodes d’extension. Je veux dire, le sucre syntaxique qui permet de chaîner les fonctions d’une manière visuellement linéaire (les unes après les autres) au lieu de les imbriquer (l’une dans l’autre). Par exemple:

     int totalEven = Enumerable.Sum(Enumerable.Where(myInts, i => i % 2 == 0)); 

    peut être écrit comme ceci:

     int totalEven = myInts.Where(i => i % 2 == 0).Sum(); 

    Vous pouvez voir comment le deuxième exemple est plus facile à lire. Vous pouvez également voir comment plus de fonctions peuvent être ajoutées avec moins de problèmes d’indentation ou les parens de fermeture de Lispy apparaissant à la fin de l’expression.

    Un grand nombre des autres réponses indiquent que Ssortingng.Join est la voie à suivre, car elle est la plus rapide ou la plus simple à lire. Mais si vous prenez mon interprétation de « manière LINQ super cool », alors la réponse est d’utiliser Ssortingng.Join mais enveloppez-le dans une méthode d’extension de style LINQ qui vous permettra d’enchaîner vos fonctions de manière agréable. Donc, si vous voulez écrire sa.Concatenate(", ") vous suffit de créer quelque chose comme ceci:

     public static class EnumerableSsortingngExtensions { public static ssortingng Concatenate(this IEnumerable ssortingngs, ssortingng separator) { return Ssortingng.Join(separator, ssortingngs); } } 

    Cela fournira un code aussi performant que l’appel direct (au moins en termes de complexité d’algorithme) et, dans certains cas, rendra le code plus lisible (selon le contexte), en particulier si un autre code du bloc utilise le style de fonction chaîné. .

    Il y a plusieurs réponses alternatives à cette question précédente – qui visait certes un tableau entier comme source, mais recevait des réponses généralisées.

    Ici, il utilise LINQ pur comme une seule expression:

     static ssortingng SsortingngJoin(ssortingng sep, IEnumerable ssortingngs) { return ssortingngs .Skip(1) .Aggregate( new SsortingngBuilder().Append(ssortingngs.FirstOrDefault() ?? ""), (sb, x) => sb.Append(sep).Append(x)); } 

    Et c’est assez rapide!

    Je vais sortingcher un peu et jeter une nouvelle réponse à cela qui semble résumer le meilleur de tout ici au lieu de le coller dans un commentaire.

    Vous pouvez donc aligner ceci:

     List ssortingngs = new List() { "one", "two", "three" }; ssortingng concat = ssortingngs .Aggregate(new SsortingngBuilder("\a"), (current, next) => current.Append(", ").Append(next)) .ToSsortingng() .Replace("\a, ",ssortingng.Empty); 

    Edit: Vous voudrez peut-être vérifier d’abord un .Replace("\a",ssortingng.Empty); vide ou append un .Replace("\a",ssortingng.Empty); à la fin de l’expression. J’imagine que j’essayais peut-être d’être un peu trop intelligent.

    La réponse de @ a.friend pourrait être légèrement plus performante, je ne suis pas sûr de ce que Remplace sous le capot par rapport à Supprimer. La seule autre mise en garde si une raison pour laquelle vous vouliez concaténer des chaînes qui se terminaient par \ a’s, vous perdriez vos séparateurs … Je trouve cela peu probable. Si tel est le cas, vous avez le choix entre d’ autres personnages .

    Vous pouvez combiner LINQ et ssortingng.join() assez efficacement. Ici, je retire un élément d’une chaîne. Il y a de meilleures façons de le faire aussi, mais voici:

     filterset = Ssortingng.Join(",", filterset.Split(',') .Where(f => mycomplicatedMatch(f,paramToMatch)) ); 

    Beaucoup de choix ici. Vous pouvez utiliser LINQ et un SsortingngBuilder pour obtenir les performances aussi:

     SsortingngBuilder builder = new SsortingngBuilder(); List MyList = new List() {"one","two","three"}; MyList.ForEach(w => builder.Append(builder.Length > 0 ? ", " + w : w)); return builder.ToSsortingng(); 

    J’ai fait ce qui suit rapidement en analysant un fichier journal IIS en utilisant linq, cela fonctionnait bien à 1 million de lignes (15 secondes), bien qu’il y ait une erreur de mémoire lors de l’essai de 2 millions de lignes.

      static void Main(ssortingng[] args) { Debug.WriteLine(DateTime.Now.ToSsortingng() + " entering main"); // USED THIS DOS COMMAND TO GET ALL THE DAILY FILES INTO A SINGLE FILE: copy *.log target.log ssortingng[] lines = File.ReadAllLines(@"C:\Log File Analysis\12-8 E5.log"); Debug.WriteLine(lines.Count().ToSsortingng()); ssortingng[] a = lines.Where(x => !x.StartsWith("#Software:") && !x.StartsWith("#Version:") && !x.StartsWith("#Date:") && !x.StartsWith("#Fields:") && !x.Contains("_vti_") && !x.Contains("/c$") && !x.Contains("/favicon.ico") && !x.Contains("/ - 80") ).ToArray(); Debug.WriteLine(a.Count().ToSsortingng()); ssortingng[] b = a .Select(l => l.Split(' ')) .Select(words => ssortingng.Join(",", words)) .ToArray() ; System.IO.File.WriteAllLines(@"C:\Log File Analysis\12-8 E5.csv", b); Debug.WriteLine(DateTime.Now.ToSsortingng() + " leaving main"); } 

    La vraie raison pour laquelle j’ai utilisé linq était pour un Distinct () dont j’avais besoin auparavant:

     ssortingng[] b = a .Select(l => l.Split(' ')) .Where(l => l.Length > 11) .Select(words => ssortingng.Format("{0},{1}", words[6].ToUpper(), // virtual dir / service words[10]) // client ip ).Distinct().ToArray() ; 

    J’ai blogué à ce sujet il y a quelque temps, ce que j’ai fait est exactement ce que vous cherchez:

    http://ondevelopment.blogspot.com/2009/02/ssortingng-concatenation-made-easy.html

    Dans le post du blog, décrivez comment implémenter des méthodes d’extension qui fonctionnent sur IEnumerable et sont nommées Concatenate, cela vous permettra d’écrire des choses comme:

     var sequence = new ssortingng[] { "foo", "bar" }; ssortingng result = sequence.Concatenate(); 

    Ou des choses plus élaborées comme:

     var methodNames = typeof(IFoo).GetMethods().Select(x => x.Name); ssortingng result = methodNames.Concatenate(", ");