Frage

Was ist der effizienteste Weg, um die alte Schule zu schreiben:

StringBuilder sb = new StringBuilder();
if (strings.Count > 0)
{
    foreach (string s in strings)
    {
        sb.Append(s + ", ");
    }
    sb.Remove(sb.Length - 2, 2);
}
return sb.ToString();

... in Linq?

War es hilfreich?

Lösung

Diese Antwort zeigt die Verwendung von Linq (Aggregate) Wie in der Frage angefordert und ist nicht für den täglichen Gebrauch bestimmt. Weil dies kein verwendet wird StringBuilder Es wird schreckliche Leistung für sehr lange Sequenzen haben. Für den regulären Code -Gebrauch String.Join Wie in den anderen gezeigt Antworten

Verwenden Sie solche aggregierten Abfragen wie diese:

string[] words = { "one", "two", "three" };
var res = words.Aggregate(
   "", // start with empty string to handle empty list case.
   (current, next) => current + ", " + next);
Console.WriteLine(res);

Dies gibt aus:

one, two, three

Ein Aggregat ist eine Funktion, die eine Sammlung von Werten nimmt und einen skalaren Wert zurückgibt. Beispiele von T-SQL sind Min, Max und Sum. Sowohl VB als auch C# unterstützen Aggregate. Sowohl VB als auch C# unterstützen Aggregate als Erweiterungsmethoden. Mit der Dot-Notation ruft man einfach eine Methode auf einem auf Ienumerable Objekt.

Denken Sie daran, dass aggregierte Abfragen sofort ausgeführt werden.

Mehr Informationen - MSDN: aggregierte Abfragen


Wenn Sie wirklich verwenden möchten Aggregate Verwenden Sie die Variante verwenden StringBuilder vorgeschlagen in Kommentar von Codemonkeyking Das wäre ungefähr der gleiche Code wie regulär String.Join einschließlich guter Leistung für eine große Anzahl von Objekten:

 var res = words.Aggregate(
     new StringBuilder(), 
     (current, next) => current.Append(current.Length == 0? "" : ", ").Append(next))
     .ToString();

Andere Tipps

return string.Join(", ", strings.ToArray());

In .NET 4 gibt es eine neue Überlast zum string.Join das akzeptiert IEnumerable<string>. Der Code würde dann aussehen wie:

return string.Join(", ", strings);

Warum Linq verwenden?

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

Das funktioniert perfekt und akzeptiert jeden IEnumerable<string> So weit ich mich erinnere. Das ist nicht nötig Aggregate Alles hier ist viel langsamer.

Haben Sie sich die aggregierte Erweiterungsmethode angesehen?

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

Echtes Beispiel aus meinem Code:

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

Eine Abfrage ist ein Objekt, das eine Namenseigenschaft hat, die eine Zeichenfolge ist, und ich möchte die Namen aller Abfragen in der ausgewählten Liste, die durch Kommas getrennt sind.

Sie können verwenden StringBuilder in Aggregate:

  List<string> strings = new List<string>() { "one", "two", "three" };

  StringBuilder sb = strings
    .Select(s => s)
    .Aggregate(new StringBuilder(), (ag, n) => ag.Append(n).Append(", "));

  if (sb.Length > 0) { sb.Remove(sb.Length - 2, 2); }

  Console.WriteLine(sb.ToString());

(Das Select ist da drin nur, um zu zeigen, dass du mehr linq machen kannst.)

Hier ist der kombinierte Join/Linq in einer ähnlichen Frage (nämlich dieses Aggregat und das Verkettungsvergleich fehlen mit 0 Elementen).

string Result = String.Join(",", split.Select(s => s.Name));

oder wenn s ist keine Zeichenfolge)

string Result = String.Join(",", split.Select(s => s.ToString()));

  • Einfach
  • leicht zu lesen und zu verstehen
  • Arbeitet für generische Elemente
  • Ermöglicht die Verwendung von Objekten oder Objekteigenschaften
  • verarbeitet den Fall von 0-Länge-Elementen
  • könnte mit zusätzlichen LINQ -Filterung verwendet werden
  • funktioniert gut (zumindest meiner Erfahrung nach)
  • erfordert keine (manuelle) Erstellung eines zusätzlichen Objekts (z. B. (z. B. StringBuilder) implementieren

Und natürlich kümmert sich bei dem lästigen Finale Comma, das manchmal in andere Ansätze einschleicht (for, foreach), deshalb habe ich überhaupt nach einer LINQ -Lösung gesucht.

Schnelle Leistungsdaten für den StringBuilder vs Select & Aggregate Case über 3000 Elemente:

Einheitstest - Dauer (Sekunden)
Linq_stringbuilder - 0.0036644
Linq_select.aggregate - 1.8012535

    [TestMethod()]
    public void LINQ_StringBuilder()
    {
        IList<int> ints = new List<int>();
        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<int> ints = new List<int>();
        for (int i = 0; i < 3000; i++)
        {
            ints.Add(i);
        }
        string ids = ints.Select(query => query.ToString())
                         .Aggregate((a, b) => a + ", " + b);
    }

Ich verwende immer die Erweiterungsmethode:

public static string JoinAsString<T>(this IEnumerable<T> input, string seperator)
{
    var ar = input.Select(i => i.ToString()).ToArray();
    return string.Join(seperator, ar);
}

Durch 'Super-cooler Linq Weg„Möglicherweise sprechen Sie über die Art und Weise, wie Linq die funktionale Programmierung mit der Verwendung von Erweiterungsmethoden viel schmackhafter macht. Ich meine, der syntaktische Zucker, der es ermöglicht, Funktionen visuell linear (eine nacheinander) anstatt zu nisten (einer im anderen). Zum Beispiel:

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

kann so geschrieben werden:

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

Sie können sehen, wie das zweite Beispiel leichter zu lesen ist. Sie können auch sehen, wie mehr Funktionen mit weniger Einkleberproblemen hinzugefügt werden können oder die Flüssig Schließen von Parens, die am Ende des Ausdrucks erscheinen.

Viele der anderen Antworten geben an, dass die String.Join ist der richtige Weg, weil es am schnellsten oder am einfachsten zu lesen ist. Aber wenn Sie meine Interpretation von 'nehmen'Super-cooler Linq Weg'Dann ist die Antwort zu verwenden String.Join Aber lassen Sie es in eine LINQ -Style -Erweiterungsmethode eingewickelt, mit der Sie Ihre Funktionen visuell ansprechend ketten können. Also, wenn du schreiben willst sa.Concatenate(", ") Sie müssen nur so etwas erstellen:

public static class EnumerableStringExtensions
{
   public static string Concatenate(this IEnumerable<string> strings, string separator)
   {
      return String.Join(separator, strings);
   }
}

Dies liefert Code, der so leistungsfähig ist wie der direkte Anruf (zumindest in Bezug .

Dies gibt verschiedene alternative Antworten Vorherige Frage - Was zugegebenermaßen auf ein Ganzzahl -Array als Quelle abzielte, aber generalisierte Antworten erhielt.

Hier verwendet es Pure LinQ als einzelne Ausdruck:

static string StringJoin(string sep, IEnumerable<string> strings) {
  return strings
    .Skip(1)
    .Aggregate(
       new StringBuilder().Append(strings.FirstOrDefault() ?? ""), 
       (sb, x) => sb.Append(sep).Append(x));
}

Und es ist verdammt schnell!

Ich werde ein wenig betrügen und eine neue Antwort darauf werfen, die das Beste von allem hier zu fassen scheint, anstatt sie in einen Kommentar zu kleben.

Sie können also eine Linie Folgendes:

List<string> strings = new List<string>() { "one", "two", "three" };

string concat = strings        
    .Aggregate(new StringBuilder("\a"), 
                    (current, next) => current.Append(", ").Append(next))
    .ToString()
    .Replace("\a, ",string.Empty); 

Bearbeiten: Entweder möchten Sie zuerst nach einem leeren aufzählbaren oder fügen Sie eine hinzu .Replace("\a",string.Empty); bis zum Ende des Ausdrucks. Ich schätze, ich hätte vielleicht versucht, ein bisschen zu schlau zu werden.

Die Antwort von @a.friend könnte etwas leistungsfähiger sein. Ich bin mir nicht sicher, was ersetzt unter der Motorhaube im Vergleich zum Entfernen tut. Die einzige andere Einschränkung, wenn Sie aus irgendeinem Grund Strings beschweren wollten, die mit A's endeten, würden Sie Ihre Separatoren verlieren ... Ich finde das unwahrscheinlich. Wenn das der Fall ist, haben Sie Andere schicke Charaktere wählen von.

You can combine LINQ and string.join() quite effectively. Here I am removing an item from a string. There are better ways of doing this too but here it is:

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

Lots of choices here. You can use LINQ and a StringBuilder so you get the performance too like so:

StringBuilder builder = new StringBuilder();
List<string> MyList = new List<string>() {"one","two","three"};

MyList.ForEach(w => builder.Append(builder.Length > 0 ? ", " + w : w));
return builder.ToString();

I did the following quick and dirty when parsing an IIS log file using linq, it worked @ 1 million lines pretty well (15 seconds), although got an out of memory error when trying 2 millions lines.

    static void Main(string[] args)
    {

        Debug.WriteLine(DateTime.Now.ToString() + " entering main");

        // USED THIS DOS COMMAND TO GET ALL THE DAILY FILES INTO A SINGLE FILE: copy *.log target.log 
        string[] lines = File.ReadAllLines(@"C:\Log File Analysis\12-8 E5.log");

        Debug.WriteLine(lines.Count().ToString());

        string[] 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().ToString());

        string[] b = a
                    .Select(l => l.Split(' '))
                    .Select(words => string.Join(",", words))
                    .ToArray()
                    ;

        System.IO.File.WriteAllLines(@"C:\Log File Analysis\12-8 E5.csv", b);

        Debug.WriteLine(DateTime.Now.ToString() + " leaving main");

    }

The real reason I used linq was for a Distinct() I neede previously:

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

I blogged about this a while ago, what I did seams to be exactly what you're looking for:

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

In the blog post describe how to implement extension methods that works on IEnumerable and are named Concatenate, this will let you write things like:

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

Or more elaborate things like:

var methodNames = typeof(IFoo).GetMethods().Select(x => x.Name);
string result = methodNames.Concatenate(", ");
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top