Domanda

Qual è il modo più efficace per scrivere alla vecchia scuola:

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?

È stato utile?

Soluzione

Questa risposta mostra l'utilizzo di LINQ (Aggregate) come richiesto nella domanda e non è destinato all'uso quotidiano. Poiché questo non utilizza un StringBuilder avrà prestazioni orribili per sequenze molto lunghe. Per il codice normale usa String.Join come mostrato nell'altra rispondi

Usa query aggregate come questa:

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

Questo output:

one, two, three

Un aggregato è una funzione che accetta una raccolta di valori e restituisce un valore scalare. Esempi di T-SQL includono min, max e sum. Sia VB che C # supportano gli aggregati. Sia VB che C # supportano aggregati come metodi di estensione. Utilizzando la notazione a punti, si chiama semplicemente un metodo su un IEnumerable oggetto.

Ricorda che le query aggregate vengono eseguite immediatamente.

Ulteriori informazioni - MSDN: Aggregate query


Se vuoi davvero usare <=> usa la variante usando <=> proposta nei commenti di CodeMonkeyKing che sarebbe circa lo stesso codice del normale <=> includendo buone prestazioni per un gran numero di oggetti:

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

Altri suggerimenti

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

In .Net 4, c'è un nuovo overload per string.Join che accetta IEnumerable < string > . Il codice sarebbe quindi simile a:

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

Perché usare Linq?

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

Funziona perfettamente e accetta qualsiasi IEnumerable < string > per quanto mi ricordo. Non è necessario Aggregate nulla qui che è molto più lento.

Hai esaminato il metodo di estensione aggregata?

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

Esempio reale dal mio codice:

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

Una query è un oggetto che ha una proprietà Name che è una stringa e voglio i nomi di tutte le query nell'elenco selezionato, separati da virgole.

Puoi usare 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());

(Il Select è lì solo per mostrare che puoi fare più cose LINQ.)

Ecco l'approccio combinato Join / Linq che ho deciso dopo aver esaminato le altre risposte e le questioni affrontate in una domanda simile (ovvero che Aggregate e Concatenate falliscono con 0 elementi).

stringa Risultato = String.Join (", " ;, split.Select (s = > s.Name));

o (se s non è una stringa)

stringa Risultato = String.Join (", " ;, split.Select (s = > s.ToString ()));

  • semplice
  • facile da leggere e comprendere
  • funziona per elementi generici
  • consente l'utilizzo di oggetti o proprietà dell'oggetto
  • gestisce il caso di elementi di lunghezza 0
  • potrebbe essere utilizzato con un filtro Linq aggiuntivo
  • si comporta bene (almeno nella mia esperienza)
  • non richiede la creazione (manuale) di un oggetto aggiuntivo (ad es. StringBuilder ) da implementare

E ovviamente Join si prende cura della fastidiosa virgola finale che a volte si insinua in altri approcci ( per , foreach ), motivo per cui stavo cercando una soluzione Linq in primo luogo.

dati rapidi sulle prestazioni di StringBuilder vs Select & amp; Caso aggregato di oltre 3000 elementi:

Test unitario - Durata (secondi)
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);
    }

Uso sempre il metodo di estensione:

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

Con ' modo LINQ super cool ' potresti parlare del modo in cui LINQ rende la programmazione funzionale molto più appetibile con l'uso di metodi di estensione. Voglio dire, lo zucchero sintattico che consente alle funzioni di essere concatenate in modo visivamente lineare (uno dopo l'altro) invece di nidificare (uno dentro l'altro). Ad esempio:

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

può essere scritto in questo modo:

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

Puoi vedere come il secondo esempio è più facile da leggere. Puoi anche vedere come è possibile aggiungere più funzioni con meno problemi di rientro o la Lispy parentesi di chiusura che appare alla fine dell'espressione.

Molte altre risposte affermano che String.Join è la strada da percorrere perché è la più veloce o più semplice da leggere. Ma se prendi la mia interpretazione di " modo LINQ super-cool ", la risposta è usare String.Join ma averlo racchiuso in un metodo di estensione in stile LINQ che consentirà voi per incatenare le vostre funzioni in modo visivamente piacevole. Quindi, se vuoi scrivere sa.Concatenate (" ;, ") devi solo creare qualcosa del genere:

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

Ciò fornirà codice altrettanto performante della chiamata diretta (almeno in termini di complessità dell'algoritmo) e in alcuni casi potrebbe rendere il codice più leggibile (a seconda del contesto) specialmente se altro codice nel blocco sta usando il stile di funzione incatenato.

Esistono varie risposte alternative in questo domanda precedente - che certamente era indirizzata a un array intero come sorgente, ma ha ricevuto risposte generalizzate.

Qui sta usando LINQ puro come singola espressione:

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

Ed è abbastanza dannatamente veloce!

Ho intenzione di imbrogliare un po 'e lanciare una nuova risposta a questo che sembra riassumere il meglio di tutto qui invece di incollarlo all'interno di un commento.

Quindi puoi una riga:

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

Modifica: O vorrai prima controllare un elenco numerato vuoto o aggiungere un . Sostituisci (" \ a ", string.Empty); nel fine dell'espressione. Immagino che avrei potuto provare a diventare un po 'troppo intelligente.

La risposta di @ a.friend potrebbe essere leggermente più performante, non sono sicuro di cosa faccia Sostituisci sotto il cofano rispetto a Rimuovi. L'unica altra avvertenza se per qualche motivo volessi concatenare stringhe che terminavano in \ a's perderei i tuoi separatori ... Lo trovo improbabile. In tal caso hai altri personaggi fantasiosi tra cui scegliere.

Puoi combinare LINQ e string.join () in modo abbastanza efficace. Qui sto rimuovendo un oggetto da una stringa. Ci sono anche modi migliori per farlo, ma eccolo qui:

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

Molte scelte qui. Puoi usare LINQ e StringBuilder in modo da ottenere prestazioni così:

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

Ho fatto quanto segue velocemente e sporco quando ho analizzato un file di registro IIS usando linq, ha funzionato abbastanza bene @ 1 milione di righe (15 secondi), anche se ho provato un errore di memoria insufficiente quando ho provato 2 milioni di righe.

    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
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()
    ;
quot;) && !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"); }

Il vero motivo per cui ho usato linq era per un Distinct () di cui avevo bisogno in precedenza:

<*>

Di tanto in tanto ho scritto un blog su questo, ciò che ho fatto le cuciture è esattamente quello che stai cercando:

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

Nel post del blog descrivi come implementare metodi di estensione che funzionano su IEnumerable e sono chiamati Concatenate, questo ti permetterà di scrivere cose come:

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

O cose più elaborate come:

var methodNames = typeof(IFoo).GetMethods().Select(x => x.Name);
string result = methodNames.Concatenate(", ");
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top