Il modo più efficace per concatenare le stringhe?

Qual è il modo più efficace per concatenare le stringhe?

Il metodo StringBuilder.Append() è molto meglio dell’utilizzo dell’operatore +. Ma ho trovato che, quando si eseguono 1000 concatenazioni o meno, String.Join() è ancora più efficiente di StringBuilder .

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

L’unico problema con String.Join è che devi concatenare le stringhe con un delimitatore comune. (Modifica 🙂 come sottolineato da @ryanversaw, puoi creare la stringa del delimitatore. Vuota.

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

Rico Mariani , il guru della performance .NET, ha pubblicato un articolo su questo argomento. Non è così semplice come si potrebbe sospettare. Il consiglio di base è questo:

Se il tuo modello assomiglia a:

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

quello è un concat ed è zippy, StringBuilder probabilmente non aiuterà.

Se il tuo modello assomiglia a:

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

allora probabilmente vorrai StringBuilder.

Ancora un altro articolo a sostegno di questa affermazione viene da Eric Lippert dove descrive le ottimizzazioni eseguite su una linea + concatenazioni in modo dettagliato.

Esistono 6 tipi di concatenazioni di stringhe:

  1. Usando il simbolo più ( + ).
  2. Utilizzando string.Concat() .
  3. Utilizzando string.Join() .
  4. Utilizzando string.Format() .
  5. Utilizzando string.Append() .
  6. Utilizzando StringBuilder .

In un esperimento, è stato dimostrato che string.Concat() è il modo migliore per avvicinarsi se le parole sono inferiori a 1000 (circa) e se le parole sono più di 1000, deve essere usato StringBuilder .

Per maggiori informazioni, controlla questo sito .

string.Join () vs string.Concat ()

Il metodo string.Concat qui è equivalente alla stringa. Richiamo del metodo Join con un separatore vuoto. Aggiungere una stringa vuota è veloce, ma non farlo è ancora più veloce, quindi il metodo string.Concat sarebbe superiore qui.

Da Chinh Do – StringBuilder non è sempre più veloce :

Regole empiriche

  • Quando si concatenano tre valori di stringa dynamic o meno, utilizzare la concatenazione di stringhe tradizionale.

  • Quando si concatenano più di tre valori di stringa dinamici, utilizzare StringBuilder.

  • Quando si costruisce una grande stringa da diversi valori letterali stringa, utilizzare il parametro @ string letterale o l’operatore inline +.

Il più delle volte StringBuilder è la soluzione migliore, ma ci sono casi come mostrato in quel post che dovresti almeno pensare ad ogni situazione.

Se stai operando in un ciclo, StringBuilder è probabilmente la strada da percorrere; ti fa risparmiare l’onere di creare nuove stringhe regolarmente. Nel codice che verrà eseguito solo una volta, tuttavia, String.Concat probabilmente sta bene.

Tuttavia, Rico Mariani (guru di ottimizzazione .NET) ha preparato un quiz in cui ha dichiarato alla fine che, nella maggior parte dei casi, raccomanda String.Format.

Da questo articolo MSDN :

C’è un sovraccarico associato alla creazione di un object StringBuilder, sia nel tempo che nella memoria. Su una macchina con memoria veloce, un StringBuilder diventa utile se stai facendo circa cinque operazioni. Come regola generale, direi che 10 o più operazioni con le stringhe sono una giustificazione per il sovraccarico su qualsiasi macchina, anche più lenta.

Quindi se ti fidi di MSDN vai con StringBuilder se devi fare più di 10 stringhe operazioni / concatenazioni – altrimenti la semplice stringa concat con ‘+’ va bene.

Ecco il metodo più veloce che mi sono evoluto nell’arco di un decennio per la mia app NLP su larga scala. Ho variazioni per IEnumerable e altri tipi di input, con e senza separatori di tipi diversi ( Char , String ), ma qui mostro il semplice caso di concatenare tutte le stringhe in una matrice in una singola stringa, senza separatore. L’ultima versione qui è sviluppata e testata in unità su C # 7 e .NET 4.7 .

Ci sono due chiavi per prestazioni più elevate; il primo consiste nel pre-calcolare l’esatta dimensione totale richiesta. Questo passaggio è banale quando l’input è una matrice come mostrato qui. Per la gestione di IEnumerable , invece, vale la pena raccogliere prima le stringhe in un array temporaneo per calcolare quel totale (la matrice è necessaria per evitare di chiamare ToString() più di una volta per elemento poiché tecnicamente, data la possibilità di effetti collaterali, fare ciò potrebbe cambiare la semantica attesa di un’operazione ‘string join’).

Successivamente, data la dimensione di allocazione totale della stringa finale, si ottiene il maggiore incremento delle prestazioni costruendo la stringa di risultati sul posto . Ciò richiede la tecnica (forse controversa) di sospendere temporaneamente l’immutabilità di una nuova String che inizialmente viene allocata piena di zeri. Qualsiasi controversia di questo tipo, comunque …

… si noti che questa è l’unica soluzione di concatenazione di massa su questa pagina che evita completamente un ulteriore giro di allocazione e copia da parte del costruttore String .

Codice completo:

 ///  /// Concatenate the strings in 'rg', none of which may be null, into a single String. ///  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); 

Devo dire che questo codice ha una leggera modifica rispetto a quello che uso io stesso. Nell’originale, chiamo l’istruzione IL di cpblk da C # per fare la copia effettiva. Per semplicità e portabilità nel codice qui, l’ho sostituito con P / Invoke memcpy , come potete vedere. Per le massime prestazioni su x64 ( ma forse non su x86 ), potresti invece utilizzare il metodo cpblk .

Aggiungendo alle altre risposte, tieni presente che a StringBuilder può essere assegnata una quantità iniziale di memoria da allocare .

Il parametro capacity definisce il numero massimo di caratteri che possono essere memorizzati nella memoria allocata dall’istanza corrente. Il suo valore è assegnato alla proprietà Capacity . Se il numero di caratteri da memorizzare nell’istanza corrente supera questo valore di capacità , l’object StringBuilder alloca memoria aggiuntiva per archiviarli.

Se la capacità è zero, viene utilizzata la capacità predefinita specifica dell’implementazione.

Aggiungere ripetutamente a un StringBuilder che non è stato pre-allocato può comportare molte allocazioni non necessarie, proprio come concatenare ripetutamente stringhe regolari.

Se si sa per quanto tempo la stringa finale sarà, può calcolarla banalmente, o può formulare un’ipotesi plausibile sul caso comune (allocare troppo non è necessariamente una cosa negativa), dovresti fornire queste informazioni al costruttore o al Proprietà di capacità . Soprattutto quando si eseguono test delle prestazioni per confrontare StringBuilder con altri metodi come String.Concat, che eseguono internamente la stessa cosa. Qualsiasi test che vedi online che non include la pre-allocazione di StringBuilder nei suoi confronti è sbagliato.

Se non riesci a indovinare la dimensione, probabilmente stai scrivendo una funzione di utilità che dovrebbe avere il suo argomento opzionale per controllare la pre-allocazione.

È anche importante sottolineare che è necessario utilizzare l’operatore + se si concatenano stringhe letterali .

Quando si concatenano stringhe letterali o costanti stringa usando l’operatore +, il compilatore crea una singola stringa. Non si verifica alcuna concatenazione del tempo di esecuzione.

Procedura: concatenare più stringhe (C # Programming Guide)

Di seguito potrebbe essere un’altra soluzione alternativa per concatenare più stringhe.

 String str1 = "sometext"; string str2 = "some other text"; string afterConcate = $"{str1}{str2}"; 

interpolazione delle stringhe

Il più efficiente è usare StringBuilder, in questo modo:

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

@jonezy: String.Concat va bene se hai un paio di piccole cose. Ma se concatenate megabyte di dati, il vostro programma probabilmente si riempie.

Dipende davvero dal tuo schema di utilizzo. Un benchmark dettagliato tra string.Join, string, Concat e string.Format può essere trovato qui: String.Format non è adatto per la registrazione intensiva

(Questa è in realtà la stessa risposta che ho dato a questa domanda)

System.String è immutabile. Quando modifichiamo il valore di una variabile di stringa, viene assegnata una nuova memoria al nuovo valore e viene rilasciata l’allocazione di memoria precedente. System.StringBuilder è stato progettato per avere il concetto di una stringa mutabile in cui è ansible eseguire una varietà di operazioni senza allocazione di memoria separata per la stringa modificata.

Prova questo 2 pezzi di codice e troverai la soluzione.

  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(); } 

Scoprirai che il primo codice terminerà molto velocemente e la memoria sarà di una buona quantità.

Il secondo codice forse la memoria sarà ok, ma ci vorrà più tempo ... ancora di più. Quindi se hai un'applicazione per molti utenti e hai bisogno di velocità, usa la 1a. Se hai un'app per un'app di un utente a breve termine, forse puoi usarla entrambe o la seconda sarà più "naturale" per gli sviluppatori.

Saluti.

Per due sole stringhe, sicuramente non vuoi usare StringBuilder. C’è qualche soglia sopra la quale il sovraccarico di StringBuilder è inferiore al sovraccarico di allocare più stringhe.

Quindi, per più di 2-3 stringhe, usa il codice di DannySmurf . Altrimenti, usa semplicemente l’operatore +.

Dipenderebbe dal codice. StringBuilder è generalmente più efficiente, ma se si concatenano solo poche stringhe e si fa tutto in un’unica riga, le ottimizzazioni del codice probabilmente si prenderanno cura di essa. È importante pensare a come appare il codice: per set più grandi StringBuilder renderà più semplice la lettura, per quelli piccoli StringBuilder aggiungerà semplicemente inutili confusione.

Un’altra soluzione:

all’interno del ciclo, usa List invece di string.

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

è molto, molto veloce.