Edited for the release of .Net Core 2.1
Repeating the test for the release of .Net Core 2.1, I get results like this
1000000 iterations of "Concat" took 842ms.
1000000 iterations of "new String" took 1009ms.
1000000 iterations of "sb" took 902ms.
In short, if you are using .Net Core 2.1 or later, Concat
is king.
I've edited the question to incorporate the valid points raised in the comments.
I was musing on my answer to a previous question and I started to wonder, is this,
return new string(charSequence.ToArray());
The best way to convert an IEnumerable<char>
to a string
. I did a little search and found this question already asked here. That answer asserts that,
string.Concat(charSequence)
is a better choice. Following an answer to this question, a StringBuilder
enumeration approach was also suggested,
var sb = new StringBuilder();
foreach (var c in chars)
{
sb.Append(c);
}
return sb.ToString();
while this may be a little unwieldy I include it for completeness. I decided I should do a little test, the code used is at the bottom.
When built in release mode, with optimizations, and run from the command line without the debugger attached I get results like this.
1000000 iterations of "Concat" took 1597ms.
1000000 iterations of "new String" took 869ms.
1000000 iterations of "sb" took 748ms.
To my reckoning, the new string(...ToArray())
is close to twice as fast as the string.Concat
method. The StringBuilder
is marginally faster still but, is awkward to use but could be an extension.
Should I stick with new string(...ToArray())
or, is there something I'm missing?
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
class Program
{
private static void Main()
{
const int iterations = 1000000;
const string testData = "Some reasonably small test data";
TestFunc(
chars => new string(chars.ToArray()),
TrueEnumerable(testData),
10,
"new String");
TestFunc(
string.Concat,
TrueEnumerable(testData),
10,
"Concat");
TestFunc(
chars =>
{
var sb = new StringBuilder();
foreach (var c in chars)
{
sb.Append(c);
}
return sb.ToString();
},
TrueEnumerable(testData),
10,
"sb");
Console.WriteLine("----------------------------------------");
TestFunc(
string.Concat,
TrueEnumerable(testData),
iterations,
"Concat");
TestFunc(
chars => new string(chars.ToArray()),
TrueEnumerable(testData),
iterations,
"new String");
TestFunc(
chars =>
{
var sb = new StringBuilder();
foreach (var c in chars)
{
sb.Append(c);
}
return sb.ToString();
},
TrueEnumerable(testData),
iterations,
"sb");
Console.ReadKey();
}
private static TResult TestFunc<TData, TResult>(
Func<TData, TResult> func,
TData testData,
int iterations,
string stage)
{
var dummyResult = default(TResult);
var stopwatch = Stopwatch.StartNew();
for (var i = 0; i < iterations; i++)
{
dummyResult = func(testData);
}
stopwatch.Stop();
Console.WriteLine(
"{0} iterations of "{2}" took {1}ms.",
iterations,
stopwatch.ElapsedMilliseconds,
stage);
return dummyResult;
}
private static IEnumerable<T> TrueEnumerable<T>(IEnumerable<T> sequence)
{
foreach (var t in sequence)
{
yield return t;
}
}
}
See Question&Answers more detail:
os