Short answer: it depends.
Long answer: if you already have an array of strings to concatenate together (with a delimiter), String.Join is the fastest way of doing it.
String.Join can look through all of the strings to work out the exact length it needs, then go again and copy all the data. This means there will be no extra copying involved. The only downside is that it has to go through the strings twice, which means potentially blowing the memory cache more times than necessary.
If you don't have the strings as an array beforehand, it's probably faster to use StringBuilder - but there will be situations where it isn't. If using a StringBuilder means doing lots and lots of copies, then building an array and then calling String.Join may well be faster.
EDIT: This is in terms of a single call to String.Join vs a bunch of calls to StringBuilder.Append. In the original question, we had two different levels of String.Join calls, so each of the nested calls would have created an intermediate string. In other words, it's even more complex and harder to guess about. I would be surprised to see either way "win" significantly (in complexity terms) with typical data.
EDIT: When I'm at home, I'll write up a benchmark which is as painful as possibly for StringBuilder. Basically if you have an array where each element is about twice the size of the previous one, and you get it just right, you should be able to force a copy for every append (of elements, not of the delimiter, although that needs to be taken into account too). At that point it's nearly as bad as simple string concatenation - but String.Join will have no problems.
Short answer: it depends.
Long answer: if you already have an array of strings to concatenate together (with a delimiter), String.Join is the fastest way of doing it.
String.Join can look through all of the strings to work out the exact length it needs, then go again and copy all the data. This means there will be no extra copying involved. The only downside is that it has to go through the strings twice, which means potentially blowing the memory cache more times than necessary.
If you don't have the strings as an array beforehand, it's probably faster to use StringBuilder - but there will be situations where it isn't. If using a StringBuilder means doing lots and lots of copies, then building an array and then calling String.Join may well be faster.
EDIT: This is in terms of a single call to String.Join vs a bunch of calls to StringBuilder.Append. In the original question, we had two different levels of String.Join calls, so each of the nested calls would have created an intermediate string. In other words, it's even more complex and harder to guess about. I would be surprised to see either way "win" significantly (in complexity terms) with typical data.
EDIT: When I'm at home, I'll write up a benchmark which is as painful as possibly for StringBuilder. Basically if you have an array where each element is about twice the size of the previous one, and you get it just right, you should be able to force a copy for every append (of elements, not of the delimiter, although that needs to be taken into account too). At that point it's nearly as bad as simple string concatenation - but String.Join will have no problems.
Here's my test rig, using int[][] for simplicity; results first:
Join: 9420ms (chk: 210710000
OneBuilder: 9021ms (chk: 210710000
(update for double results:)
Join: 11635ms (chk: 210710000
OneBuilder: 11385ms (chk: 210710000
(update re 2048 * 64 * 150)
Join: 11620ms (chk: 206409600
OneBuilder: 11132ms (chk: 206409600
and with OptimizeForTesting enabled:
Join: 11180ms (chk: 206409600
OneBuilder: 10784ms (chk: 206409600
So faster, but not massively so; rig (run at console, in release mode, etc):
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace ConsoleApplication2
{
class Program
{
static void Collect()
{
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
}
static void Main(string[] args)
{
const int ROWS = 500, COLS = 20, LOOPS = 2000;
int[][] data = new int[ROWS][];
Random rand = new Random(123456);
for (int row = 0; row < ROWS; row++)
{
int[] cells = new int[COLS];
for (int col = 0; col < COLS; col++)
{
cells[col] = rand.Next();
}
data[row] = cells;
}
Collect();
int chksum = 0;
Stopwatch watch = Stopwatch.StartNew();
for (int i = 0; i < LOOPS; i++)
{
chksum += Join(data).Length;
}
watch.Stop();
Console.WriteLine("Join: {0}ms (chk: {1}", watch.ElapsedMilliseconds, chksum);
Collect();
chksum = 0;
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOPS; i++)
{
chksum += OneBuilder(data).Length;
}
watch.Stop();
Console.WriteLine("OneBuilder: {0}ms (chk: {1}", watch.ElapsedMilliseconds, chksum);
Console.WriteLine("done");
Console.ReadLine();
}
public static string Join(int[][] array)
{
return String.Join(Environment.NewLine,
Array.ConvertAll(array,
row => String.Join(",",
Array.ConvertAll(row, x => x.ToString()))));
}
public static string OneBuilder(IEnumerable<int[]> source)
{
StringBuilder sb = new StringBuilder();
bool firstRow = true;
foreach (var row in source)
{
if (firstRow)
{
firstRow = false;
}
else
{
sb.AppendLine();
}
if (row.Length > 0)
{
sb.Append(row[0]);
for (int i = 1; i < row.Length; i++)
{
sb.Append(',').Append(row[i]);
}
}
}
return sb.ToString();
}
}
}
java - String.join() vs other string concatenation operations - Stack Overflow
Why doesn't C#'s String.Join use StringBuilder at one point? - Stack Overflow
Discovered comparison of Performance Of String Concatenation
In Java 8 we can finally join strings
String.join relies on the class StringJoiner which itself relies on an internal StringBuilder to build the joined string.
So performance-wise it's much the same as using a StringBuilder and appending to it, or using a chain of + (which nowadays are converted to StringBuilder operations by the compiler).
But the significance of String.join is not as a general replacement for + or String.concat, but in being the "reverse operation" of a String.split operation. It makes more sense in that context - when you have a bunch of strings that you want to join together using a delimiter - than as a replacement for concat.
That is, to build an output like "a/b/c/d" or "(a+b+c+d)" when you have a,b,c and d in an array or a list, String.join or a StringJoiner would make the operation clear and readable.
str1 + " " + str2 is internally converted into:
StringBuffer tmp1 = new StringBuffer();
tmp1.append(str1);
tmp1.append(" ");
String tmp2 = tmp1.toString();
StringBuffer tmp3 = new StringBuffer();
tmp3.append(tmp2);
tmp3.append(str2);
String result = tmp3.toString();
str1.concat(str2) will not produce the same result, as the space wont be present between the two strings.
join should be equivalent to
StringBuffer tmp1 = new StringBuffer();
tmp1.append(str1);
tmp1.append(" ");
tmp1.append(str2);
String result = tmp.toString();
and hence be faster.
After waiting for 55 minutes using text+= 137k times in a loop, I have googled c# performance one string vs multiple string variables. Although I have not found the answer, this article made me think that I should first try another method before creating a lot of temp variables:
https://dotnetcoretutorials.com/2020/02/06/performance-of-string-concatenation-in-c/
Update: I have just replaced all string+= with StringBuilder.Append. It is now all done in 1.243 second. Yay. Thanks to all recommending StringBuilder
So I always hear that StringBuilder is the better, more efficient option... but is that true? How much more efficient is it? Is it worth it?
So lets say I have a method that returns a greeting. With old-school concatenation I can write something simple, and clear:
string _myName = "Bob";
public string GetGreeting(personName)
{
return "Hello " + personName+ ", my name is " + _myName + "!";
}With StringBuilder I have to do something much more space-consuming, which in turn is less clear.
string _myName = "Bob";
public string GetGreeting(personName)
{
StringBuilding myString = new StringBuilder("Hello ");
myString.Append(personName);
myString.Append(", my name is ");
myString.Append(myName);
myString.Append("!");
return myString.ToString();
}To me, the second example is the worse code. It's harder to read, it took up more space, and it looks like it does far more work -- considering I had to convert myString back to .ToString() (although looks can be decieving) -- so is it always best to use StringBuilder?
(I'm a lone programmer at my shop so I don't have anyone to gather opinions from. Just web articles and you guys... really appreciate the help. I'm trying to be a better developer)
EDIT: Thanks everybody, as always you guys are a big help and a great source of information!