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;
}
}
}
It's worth noting that these results, whilst true for the case of IEnumerable from a purists point of view, are not always thus. For example if you were to actually have a char array even if you are passed it as an IEnumerable it is faster to call the string constructor.
The results:
Sending String as IEnumerable<char>
10000 iterations of "new string" took 157ms.
10000 iterations of "sb inline" took 150ms.
10000 iterations of "string.Concat" took 237ms.
========================================
Sending char[] as IEnumerable<char>
10000 iterations of "new string" took 10ms.
10000 iterations of "sb inline" took 168ms.
10000 iterations of "string.Concat" took 273ms.
The Code:
static void Main(string[] args)
{
TestCreation(10000, 1000);
Console.ReadLine();
}
private static void TestCreation(int iterations, int length)
{
char[] chars = GetChars(length).ToArray();
string str = new string(chars);
Console.WriteLine("Sending String as IEnumerable<char>");
TestCreateMethod(str, iterations);
Console.WriteLine("===========================================================");
Console.WriteLine("Sending char[] as IEnumerable<char>");
TestCreateMethod(chars, iterations);
Console.ReadKey();
}
private static void TestCreateMethod(IEnumerable<char> testData, int iterations)
{
TestFunc(chars => new string(chars.ToArray()), testData, iterations, "new string");
TestFunc(chars =>
{
var sb = new StringBuilder();
foreach (var c in chars)
{
sb.Append(c);
}
return sb.ToString();
}, testData, iterations, "sb inline");
TestFunc(string.Concat, testData, iterations, "string.Concat");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With