7

I need to concatenate a lot of strings alltogether and put a comma between any of them. I have a list of strings

"123123123213"
"1232113213213"
"123213123"

and I want to get

"123123123213,1232113213213,123213123"

I was wondering what is the best way to achieve that.

I could do this like this:

private List<string> stringList = new List<string> { 
    // a lot of strings in here
    "1234567890", "34343434", "4343434" }; 

string outcome = string.Join(",", stringList.ToArray());

Or maybe:

StringBuilder builder = new StringBuilder();
stringList.ForEach(val => {
    builder.Append(val);
    builder.Append(",");
});

string outcome = builder.ToString();

Which way is better? Do you know better ways to concatenate strings?

casperOne
  • 73,706
  • 19
  • 184
  • 253
image
  • 173
  • 1
  • 2
  • 5

11 Answers11

6

As @Ekkehard said, use the string.Join.

However, you do not need the ToArray() because string.Join has an overload for IEnumerable<string>.

List<string> stringList = new List<string> 
    { "1234567890", "34343434", "4343434" }; 

string outcome = string.Join(",", stringList);

EDIT

As @Kobi said, this will work only C# 4.0. In 3.5 I would do.

var s = new StringBuilder(stringList.Count * 8);
foreach (var item in stringList)
{
   s.Append(item);
   s.Append(',');
}
s.Length -= 1;
string outcome = stringList.ToList();
Community
  • 1
  • 1
Richard Schneider
  • 34,944
  • 9
  • 57
  • 73
5

You should use string.Join() because:

a) it's much more readable, maintainable and easy on the eyes.

b) it uses a StringBuilder internally already, so it's very efficient ( you can confirm yourself using Reflector).

Edit:

string.Join() uses a StringBuilder for the general case of an IEnumerable<T> input. If you already have an array on the other hand it uses some voodoo magic (including FastAllocateString() and UnSafeCharBuffer) to be even faster.

BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
  • FYI, `string.Join(string, string[])` *does not* use `StringBuilder`, but `UnSafeCharBuffer`. – svick May 01 '11 at 21:21
  • @svick: Yes just was in the process of editing that in after making that observation as well- it's vodoo magic indeed ;-) – BrokenGlass May 01 '11 at 21:24
1

Use Join, because it doesn't add a trailing ",".

Ekkehard.Horner
  • 38,498
  • 2
  • 45
  • 96
1

There's a benchmark on this page that seems to show that string.Join performs better than StringBuilder on a small array in a lot of iterations. you should probably benchmark for larger arrays also. As I'm posting this I see that BrokenGlass answered that StringBuilder is used internally in string.Join so you can expect it to be faster I guess.

Jan
  • 8,011
  • 3
  • 38
  • 60
1

Your second solution adds an extra , at the end. Take a look at Eric Lippert`s blog entry

I would recommend fixing your second solution. A StringBuilder would be definitely faster, as you avoid coping the list contents to a new array.

StringBuilder builder = new StringBuilder();
string separator = "";
stringList.ForEach(
    val =>
    {
        builder.Append(separator).Append(val);
        separator = ",";
    });
string outcome = builder.ToString();
Fede
  • 3,928
  • 1
  • 20
  • 28
0

StringBuilder is a very efficient way and would be recommended here.

Kevin Hsu
  • 1,726
  • 11
  • 14
  • Except `string.Join()` can be even more effective (at least in the case, when you give it `string[]`, otherwise is uses `StringBuilder` itself). – svick May 01 '11 at 21:18
  • svick you have given a -1 to somebody that said something more clever than you. And however the asker needs it for a list of strings not for an array. – Marino Šimić May 01 '11 at 21:20
  • @Marino, how is using `StringBuilder` more clever than using `string.Join()`? The latter is much more clearer, less error prone (you don't have to write your own code) and possibly faster. – svick May 01 '11 at 21:23
  • Gosh, it is just an alternative. – Kevin Hsu May 01 '11 at 22:55
  • To use string.join you have to take the list and first make an array. That may not be the most efficient way, especially if you have a lot of little strings. – Kevin Hsu May 01 '11 at 23:15
0

This adhoc implementation I tried with the StrignBuilder is faster than String.Join. More than that String.Join is a MEMORY HOG. I tried with 20000000 strings and String.Join always gives OutOfMemory, when my implementation finishes. On your machine It may be even on less strings if you have less than 8Gb of memory. Comment one of the implementations to test. This holds true unless you use a fixed string[] array. String.Join is good there.

   public static void Main(string[] Args)
    {
        Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

          List<string> strings = new List<string>() {};
        for (double d = 0; d < 8000000; d++) {
            strings.Add(d.ToString());
        }

        TimeSpan upTime;
        TimeSpan newupTime;
        using (var pc = new PerformanceCounter("System", "System Up Time"))
        {
            StringBuilder sb = new StringBuilder(strings.Count);
            int i;

            pc.NextValue();    //The first call returns 0, so call this twice
            upTime = TimeSpan.FromSeconds(pc.NextValue());

            for (i = 0; i < strings.Count - 1; i++)
            {
                sb.Append(strings[i]);
                sb.Append(",");
            }
            sb.Append(strings[i]);

            newupTime = TimeSpan.FromSeconds(pc.NextValue());
            sb = null;
            Console.WriteLine("SB " + (newupTime - upTime).TotalMilliseconds);
        }

        using (var pc = new PerformanceCounter("System", "System Up Time"))
        {

            pc.NextValue();
            upTime = TimeSpan.FromSeconds(pc.NextValue());

            string s = string.Join(",", strings);

            newupTime = TimeSpan.FromSeconds(pc.NextValue());
            Console.WriteLine("JOIN " + (newupTime - upTime).TotalMilliseconds);
        }


    }
SB 406
JOIN 484
Marino Šimić
  • 7,318
  • 1
  • 31
  • 61
0

According to the following test I've made, Join is 3x faster faster on large arrays:

The Text.txt file contains the value "aaaaaaaaaaaaaaaaaaa" on 38400 lines:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      var strings = File.ReadAllLines("Text.txt");

      Stopwatch sw;

      StringBuilder sb = new StringBuilder();

      sw = Stopwatch.StartNew();
      for (int i = 0; i < strings.Length; i++)
      {
        sb.AppendLine(strings[i]);
      }
      sw.Stop();
      TimeSpan sbTime = sw.Elapsed;

      sw = Stopwatch.StartNew();
     var output = string.Join(",", strings);
     sw.Stop();

     TimeSpan joinTime = sw.Elapsed;   

    }
  }
}

Output:

00:00:00.0098754
00:00:00.0032922
Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
0

String.Join is the fastest if you have a fixed number of strings to join. The deeper reason is that String.Join does loop over the array and allocates the final string buffer with the right size because it does in the first pass add the string length of all strings together. You can get similar results when you play around with StringBuilder and its capacity. The golden rule is to spare memory allocations at the cost of looping over the array two times. Which approach is faster depends on how many items you have in your list and how big the resultint string will get.

Yours, Alois Kraus

Alois Kraus
  • 13,229
  • 1
  • 38
  • 64
0

Test code:

public static void Performance(Action fn)
{
    var timer = new Stopwatch();
    timer.Start();

    for (var i = 0; i < 10000000; ++i)
    {
        fn();
    }

    timer.Stop();

    Console.WriteLine("{0} Time: {1}ms ({2})", fn.ToString(), timer.ElapsedMilliseconds, timer.ElapsedTicks);
}

static void Main(string[] args)
{
    var stringList = new List<string>() {
        "123123123213",
        "1232113213213",
        "123213123"
    };

    string outcome = String.Empty;
    Performance(() =>
    {
        outcome = string.Join(",", stringList);
    });

    Console.WriteLine(outcome);

    Performance(() =>
    {
        StringBuilder builder = new StringBuilder();
        stringList.ForEach
            (
                val =>
                {
                    builder.Append(val);
                    builder.Append(",");
                }
            );
        outcome = builder.ToString();
        outcome = outcome.Substring(0, outcome.Length - 1);
    });

    Console.WriteLine(outcome);

    Console.ReadKey();

}

Result 1. String.Join - 2. StringBuilder + SubString. ####ms (ticks)

result

In this case String.Join is faster, but if you are ok with a trailing , then

string builder

StringBuilder is slightly faster (with a trailing ,).

BrunoLM
  • 97,872
  • 84
  • 296
  • 452
0

If one wants to be cool and run on Heavy Fuel use Aggregate

List<string> stringList = new List<string> { "1234567890", "34343434", "4343434" };

Console.WriteLine( stringList.Aggregate( ( current, next ) => string.Format( "{0}, {1}", current, next ) ) );

// Outputs:   1234567890, 34343434, 4343434
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122