Frage

Was ist der effizienteste Weg, Zeichenfolgen zu verketten?

War es hilfreich?

Lösung

Der StringBuilder.Append() Methode ist viel besser als die Verwendung des +-Operators.Aber ich habe festgestellt, dass bei der Ausführung von 1000 Verkettungen oder weniger String.Join() ist noch effizienter als StringBuilder.

StringBuilder sb = new StringBuilder();
sb.Append(someString);

Das einzige Problem mit String.Join besteht darin, dass Sie die Zeichenfolgen mit einem gemeinsamen Trennzeichen verketten müssen.(Bearbeiten:) Wie @ryanversaw betonte, können Sie das Trennzeichen string.leer machen.

string key = String.Join("_", new String[] 
{ "Customers_Contacts", customerID, database, SessionID });

Andere Tipps

Rico Mariani, der .NET-Performance-Guru, hatte ein Artikel zu genau diesem Thema.Es ist nicht so einfach, wie man vermuten könnte.Der grundlegende Rat ist dieser:

Wenn Ihr Muster so aussieht:

x = f1(...) + f2(...) + f3(...) + f4(...)

Das ist ein Concat und es ist flott, StringBuilder wird wahrscheinlich nicht helfen.

Wenn Ihr Muster so aussieht:

if (...) x += f1(...)
if (...) x += f2(...)
if (...) x += f3(...)
if (...) x += f4(...)

dann möchten Sie wahrscheinlich StringBuilder.

Noch ein Artikel, der diese Behauptung untermauert stammt von Eric Lippert, wo er die an einer Zeile durchgeführten Optimierungen beschreibt + Verkettungen im Detail.

Es gibt 6 Arten von Zeichenfolgenverkettungen:

  1. Mit dem Pluszeichen (+)-Symbol.
  2. Benutzen string.Concat().
  3. Benutzen string.Join().
  4. Benutzen string.Format().
  5. Benutzen string.Append().
  6. Benutzen StringBuilder.

In einem Experiment wurde das bewiesen string.Concat() ist der beste Ansatz, wenn die Anzahl der Wörter (ungefähr) weniger als 1000 beträgt, und wenn die Anzahl der Wörter mehr als 1000 beträgt StringBuilder sollte benutzt werden.

Weitere Informationen finden Sie hier Website.

string.Join() vs. string.Concat()

Die string.Concat-Methode entspricht hier dem Aufruf der string.Join-Methode mit einem leeren Trennzeichen.Das Anhängen einer leeren Zeichenfolge ist schnell, aber es ist sogar noch schneller, dies nicht zu tun string.Concat Methode wäre hier überlegen.

Aus Chinh Do - StringBuilder ist nicht immer schneller:

Faustregeln

  • Wenn Sie drei dynamische Zeichenfolgenwerte oder weniger verketten, verwenden Sie die herkömmliche Zeichenfolgenverkettung.

  • Wenn Sie mehr als drei dynamische Zeichenfolgenwerte verketten, verwenden Sie StringBuilder.

  • Wenn Sie eine große Zeichenfolge aus mehreren Zeichenfolgenliteralen erstellen, verwenden Sie entweder das Zeichenfolgenliteral @ oder den Inline-Operator +.

Am meisten In den meisten Fällen ist StringBuilder die beste Wahl, aber es gibt Fälle, wie in diesem Beitrag gezeigt, in denen Sie zumindest über jede Situation nachdenken sollten.

Wenn Sie in einer Schleife arbeiten, ist StringBuilder wahrscheinlich die richtige Wahl.Es erspart Ihnen den Aufwand, regelmäßig neue Zeichenfolgen zu erstellen.In Code, der nur einmal ausgeführt wird, ist String.Concat jedoch wahrscheinlich in Ordnung.

Rico Mariani (.NET-Optimierungsguru) habe ein Quiz ausgedacht in dem er am Ende feststellte, dass er in den meisten Fällen String.Format empfiehlt.

Hier ist die schnellste Methode, die ich über ein Jahrzehnt für meine groß angelegte NLP-App entwickelt habe.Ich habe Variationen für IEnumerable<T> und andere Eingabetypen, mit und ohne Trennzeichen unterschiedlicher Art (Char, String), aber hier zeige ich den einfachen Fall von Verketten aller Zeichenfolgen in einem Array in eine einzelne Zeichenfolge ohne Trennzeichen.Die neueste Version hier wurde entwickelt und getestet C# 7 Und .NET 4.7.

Es gibt zwei Schlüssel zu höherer Leistung;Die erste besteht darin, die genaue erforderliche Gesamtgröße vorab zu berechnen.Dieser Schritt ist trivial, wenn die Eingabe ein Array ist, wie hier gezeigt.Zur Handhabung IEnumerable<T> Stattdessen lohnt es sich, die Zeichenfolgen zunächst in einem temporären Array zu sammeln, um diese Gesamtsumme zu berechnen (Das Array ist erforderlich, um einen Aufruf zu vermeiden ToString() mehr als einmal pro Element, da dies technisch gesehen und angesichts der Möglichkeit von Nebenwirkungen die erwartete Semantik einer „String-Join“-Operation ändern könnte.

Als nächstes wird angesichts der Gesamtzuteilungsgröße der endgültigen Zeichenfolge die größte Leistungssteigerung erzielt Erstellen der Ergebniszeichenfolge direkt.Dies erfordert die (vielleicht umstrittene) Technik, die Unveränderlichkeit eines Neuen vorübergehend außer Kraft zu setzen String die zunächst voller Nullen allokiert wird.Abgesehen von solchen Kontroversen ...

...beachten Sie, dass dies die einzige Massenverkettungslösung auf dieser Seite ist, die eine vollständig vermeidet zusätzliche Runde des Zuordnens und Kopierens bis zum String Konstrukteur.

Vollständiger Code:

/// <summary>
/// Concatenate the strings in 'rg', none of which may be null, into a single String.
/// </summary>
public static unsafe String StringJoin(this String[] rg)
{
    int i;
    if (rg == null || (i = rg.Length) == 0)
        return String.Empty;

    if (i == 1)
        return rg[0];

    String s, t;
    int cch = 0;
    do
        cch += rg[--i].Length;
    while (i > 0);
    if (cch == 0)
        return String.Empty;

    i = rg.Length;
    fixed (Char* _p = (s = new String(default(Char), cch)))
    {
        Char* pDst = _p + cch;
        do
            if ((t = rg[--i]).Length > 0)
                fixed (Char* pSrc = t)
                    memcpy(pDst -= t.Length, pSrc, (UIntPtr)(t.Length << 1));
        while (pDst > _p);
    }
    return s;
}

[DllImport("MSVCR120_CLR0400", CallingConvention = CallingConvention.Cdecl)]
static extern unsafe void* memcpy(void* dest, void* src, UIntPtr cb);

Ich sollte erwähnen, dass dieser Code eine leichte Änderung gegenüber dem aufweist, was ich selbst verwende.Im Original I Ruf den cpblk IL-Anweisung aus C# um das eigentliche Kopieren durchzuführen.Der Einfachheit und Portabilität halber habe ich den Code hier durch P/Invoke ersetzt memcpy stattdessen, wie Sie sehen können.Für höchste Leistung auf x64 (aber vielleicht nicht x86) möchten Sie vielleicht die verwenden cpblk Methode statt.

Davon MSDN-Artikel:

Es gibt einige Overheads, die mit dem Erstellen eines StringBuilder -Objekts sowohl zeitlich als auch speicher erstellt werden.Auf einer Maschine mit schnellem Speicher lohnt sich ein StringBuilder, wenn Sie ungefähr fünf Vorgänge ausführen.Als Faustregel würde ich sagen, 10 oder mehr String -Operationen sind eine Rechtfertigung für den Overhead auf jeder Maschine, sogar eine langsamere.

Wenn Sie also MSDN vertrauen, verwenden Sie StringBuilder, wenn Sie mehr als 10 String-Operationen/Verkettungen durchführen müssen – andernfalls ist eine einfache String-Verknüpfung mit „+“ in Ordnung.

Bitte beachten Sie dies, wenn Sie die anderen Antworten ergänzen StringBuilder kann eine anfängliche Menge an Speicher zugewiesen werden, die er zuweisen soll.

Der Kapazität Der Parameter definiert die maximale Anzahl von Zeichen, die im von der aktuellen Instanz zugewiesenen Speicher gespeichert werden können.Sein Wert wird dem zugewiesen Kapazität Eigentum.Wenn die Anzahl der in der aktuellen Instanz zu speichernden Zeichen diese überschreitet Kapazität Wert, weist das StringBuilder-Objekt zusätzlichen Speicher zu, um sie zu speichern.

Wenn Kapazität Null ist, wird die Implementierungsspezifische Standardkapazität verwendet.

Das wiederholte Anhängen an einen StringBuilder, der nicht vorab zugewiesen wurde, kann zu vielen unnötigen Zuweisungen führen, genau wie das wiederholte Verketten regulärer Zeichenfolgen.

Wenn Sie wissen, wie lang die endgültige Zeichenfolge sein wird, sie trivial berechnen können oder eine fundierte Vermutung über den allgemeinen Fall anstellen können (zu viel Zuweisung ist nicht unbedingt eine schlechte Sache), sollten Sie diese Informationen dem Konstruktor oder dem Konstruktor zur Verfügung stellen Kapazität Eigentum. Besonders beim Ausführen von Leistungstests, um StringBuilder mit anderen Methoden wie String.Concat zu vergleichen, die intern dasselbe tun.Jeder Test, den Sie online sehen und der die StringBuilder-Vorbelegung nicht in seine Vergleiche einbezieht, ist falsch.

Wenn Sie die Größe nicht einschätzen können, schreiben Sie wahrscheinlich eine Hilfsfunktion, die über ein eigenes optionales Argument zur Steuerung der Vorabzuweisung verfügen sollte.

Es ist auch wichtig, darauf hinzuweisen, dass Sie das verwenden sollten + Operator, wenn Sie verketten String-Literale.

Wenn Sie Zeichenfolgenliterale oder Zeichenfolgenkonstanten mit dem Operator „+“ verketten, erstellt der Compiler eine einzelne Zeichenfolge.Es findet keine Laufzeitverkettung statt.

Wie man:Mehrere Zeichenfolgen verketten (C#-Programmierhandbuch)

Im Folgenden finden Sie möglicherweise eine weitere alternative Lösung zum Verketten mehrerer Zeichenfolgen.

String str1 = "sometext";
string str2 = "some other text";

string afterConcate = $"{str1}{str2}";

String-Interpolation

Am effizientesten ist die Verwendung von StringBuilder, etwa so:

StringBuilder sb = new StringBuilder();
sb.Append("string1");
sb.Append("string2");
...etc...
String strResult = sb.ToString();

@jonezy:String.Concat ist in Ordnung, wenn Sie ein paar kleine Dinge haben.Aber wenn Sie Megabytes an Daten verketten, wird Ihr Programm wahrscheinlich scheitern.

Probieren Sie diese beiden Codeteile aus und Sie werden die Lösung finden.

 static void Main(string[] args)
    {
        StringBuilder s = new StringBuilder();
        for (int i = 0; i < 10000000; i++)
        {
            s.Append( i.ToString());
        }
        Console.Write("End");
        Console.Read();
    }

Vs

static void Main(string[] args)
    {
        string s = "";
        for (int i = 0; i < 10000000; i++)
        {
            s += i.ToString();
        }
        Console.Write("End");
        Console.Read();
    }

Sie werden feststellen, dass der erste Code sehr schnell endet und der Speicher ausreichend ist.

Mit dem zweiten Code ist der Speicher vielleicht in Ordnung, aber es wird länger dauern ...viel länger.Wenn Sie also eine Anwendung für viele Benutzer haben und Geschwindigkeit benötigen, verwenden Sie die erste.Wenn Sie eine App für eine kurzfristige Ein-Benutzer-App haben, können Sie möglicherweise beide verwenden, da sonst die zweite für Entwickler „natürlicher“ ist.

Prost.

System.String ist unveränderlich.Wenn wir den Wert einer Zeichenfolgenvariablen ändern, wird dem neuen Wert ein neuer Speicher zugewiesen und die vorherige Speicherzuweisung freigegeben.System.StringBuilder wurde entwickelt, um das Konzept einer veränderlichen Zeichenfolge zu verfolgen, in der eine Vielzahl von Vorgängen ausgeführt werden können, ohne dass der geänderten Zeichenfolge ein separater Speicherort zugewiesen werden muss.

Eine andere Lösung:

Verwenden Sie innerhalb der Schleife List anstelle von String.

List<string> lst= new List<string>();

for(int i=0; i<100000; i++){
    ...........
    lst.Add(...);
}
return String.Join("", lst.ToArray());;

es ist sehr, sehr schnell.

Es hängt wirklich von Ihrem Nutzungsmuster ab.Einen detaillierten Benchmark zwischen string.Join, string,Concat und string.Format finden Sie hier: String.Format ist nicht für intensive Protokollierung geeignet

(Das ist eigentlich die gleiche Antwort, die ich gegeben habe Das Frage)

Für nur zwei Strings möchten Sie StringBuilder auf keinen Fall verwenden.Es gibt einen bestimmten Schwellenwert, ab dem der StringBuilder-Overhead geringer ist als der Overhead für die Zuweisung mehrerer Strings.

Verwenden Sie also für mehr als 2-3 Saiten DannySmurfs Code.Andernfalls verwenden Sie einfach den Operator +.

Es würde vom Code abhängen.StringBuilder ist im Allgemeinen effizienter, aber wenn Sie nur ein paar Strings verketten und alles in einer Zeile erledigen, werden Codeoptimierungen dies wahrscheinlich für Sie erledigen.Es ist auch wichtig, darüber nachzudenken, wie der Code aussieht:Bei größeren Sätzen erleichtert StringBuilder die Lesbarkeit, bei kleinen sorgt StringBuilder nur für unnötige Unordnung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top