You can use String.Concat()
.
var allowedString = String.Concat(
inputString.Where(c => allowedChars.Contains(c))
);
Caveat: This approach will have some performance implications. String.Concat
doesn't special case collections of characters so it performs as if every character was converted to a string then concatenated as mentioned in the documentation (and it actually does). Sure this gives you a builtin way to accomplish this task, but it could be done better.
I don't think there are any implementations within the framework that will special case char
so you'll have to implement it. A simple loop appending characters to a string builder is simple enough to create.
Here's some benchmarks I took on a dev machine and it looks about right.
1000000 iterations on a 300 character sequence on a 32-bit release build:
ToArrayString: 00:00:03.1695463 Concat: 00:00:07.2518054 StringBuilderChars: 00:00:03.1335455 StringBuilderStrings: 00:00:06.4618266
static readonly IEnumerable<char> seq = Enumerable.Repeat('a', 300);
static string ToArrayString(IEnumerable<char> charSequence)
{
return new String(charSequence.ToArray());
}
static string Concat(IEnumerable<char> charSequence)
{
return String.Concat(charSequence);
}
static string StringBuilderChars(IEnumerable<char> charSequence)
{
var sb = new StringBuilder();
foreach (var c in charSequence)
{
sb.Append(c);
}
return sb.ToString();
}
static string StringBuilderStrings(IEnumerable<char> charSequence)
{
var sb = new StringBuilder();
foreach (var c in charSequence)
{
sb.Append(c.ToString());
}
return sb.ToString();
}
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.
See MS blog post for more details.
I've made this the subject of another question but more and more, that is becoming a direct answer to this question.
I've done some performance testing of 3 simple methods of converting an IEnumerable<char>
to a string
, those methods are
new string
return new string(charSequence.ToArray());
Concat
return string.Concat(charSequence)
StringBuilder
var sb = new StringBuilder();
foreach (var c in charSequence)
{
sb.Append(c);
}
return sb.ToString();
In my testing, that is detailed in the linked question, for 1000000
iterations of "Some reasonably small test data"
I get results like this,
1000000 iterations of "Concat" took 1597ms.
1000000 iterations of "new string" took 869ms.
1000000 iterations of "StringBuilder" took 748ms.
This suggests to me that there is not good reason to use string.Concat
for this task. If you want simplicity use the new string approach and if want performance use the StringBuilder.
I would caveat my assertion, in practice all these methods work fine, and this could all be over optimization.
As of .NET 4, many string methods take IEnumerable as arguments.
string.Concat(myEnumerable);
Here is a more succinct version of the StringBuilder answer:
return charSequence.Aggregate(new StringBuilder(), (seed, c) => seed.Append(c)).ToString();
I timed this using the same tests that Jeff Mercado used and this was 1 second slower across 1,000,000 iterations on the same 300 character sequence (32-bit release build) than the more explicit:
static string StringBuilderChars(IEnumerable<char> charSequence)
{
var sb = new StringBuilder();
foreach (var c in charSequence)
{
sb.Append(c);
}
return sb.ToString();
}
So if you're a fan of accumulators then here you go.
My data is contrary to the results Jodrell posted. First have a look at the extension methods I use:
public static string AsStringConcat(this IEnumerable<char> characters)
{
return String.Concat(characters);
}
public static string AsStringNew(this IEnumerable<char> characters)
{
return new String(characters.ToArray());
}
public static string AsStringSb(this IEnumerable<char> characters)
{
StringBuilder sb = new StringBuilder();
foreach (char c in characters)
{
sb.Append(c);
}
return sb.ToString();
}
With
Input
((IEnumerable<char>)RandomString(STRLEN)).Reverse()
Results
Input
((IEnumerable<char>)RandomString(STRLEN)).Take((int)ITERATIONS/2)
Results
Input
((IEnumerable<char>)RandomString(STRLEN))
(this is just an upcast)
Results
I ran this on an Intel i5 760 targeting .NET Framework 3.5.
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