IEnumerable <string>string

我从来没有偶然发现过,但我现在很惊讶,我找不到一个真正简单的方法来将IEnumerable<char>转换为string

我能想到的最好的方法是string str = new string(myEnumerable.ToArray()); ,但对我来说,似乎这会创build一个新的char[] ,然后从中创build一个新的string ,这看起来很昂贵。

我会认为这将是在.NET框架内build立的通用function。 有一个更简单的方法来做到这一点?

对于那些感兴趣的,我想使用这个的原因是使用LINQ过滤string:

 string allowedString = new string(inputString.Where(c => allowedChars.Contains(c)).ToArray()); 

你可以使用String.Concat()

 var allowedString = String.Concat( inputString.Where(c => allowedChars.Contains(c)) ); 

警告 :这种方法会有一些性能影响。 String.Concat并不是特殊的字符集合,所以它的performance就好像每个字符都被转换成了一个string,然后如文档中提到的那样连接起来( 实际上它是这样的 )。 当然,这给你一个内在的方式来完成这个任务,但它可以做得更好。

我不认为框架中有任何实现将特殊情况char所以你必须实现它。 将字符附加到string生成器的简单循环很容易创build。


这是我在开发机器上的一些基准,看起来是正确的。

在32位版本上的300字符序列上进行1000000次迭代:

 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(); } 

我已经把这个问题作为另一个问题,但越来越多,这就成为对这个问题的直接回答。

我已经做了一些将IEnumerable<char>转换为string的3个简单方法的性能testing,这些方法是

新的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(); 

在我的testing中,详细的链接问题 ,对于"Some reasonably small test data" 1000000次迭代,我得到这样的结果,

“Concat”的1000000次迭代耗时1597ms。

“新string”1000000次迭代耗时869ms。

“StringBuilder”的1000000次迭代耗时748ms。

这暗示了对于这个任务使用string.Concat没有很好的理由。 如果你想简单的使用新的string方法,如果要性能使用StringBuilder

我会告诫我的断言,实际上所有这些方法工作正常,这可能都是过度优化。

从.NET 4开始,许多string方法都以IEnumerable作为参数。

 string.Concat(myEnumerable); 

我的数据与Jodrell发布的结果相反。 首先看看我使用的扩展方法:

 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(); } 

我的结果

  • STRLEN = 31
  • ITERATIONS = 1000000

input

  • ((IEnumerable<char>)RandomString(STRLEN)).Reverse()

结果

  • Concat:1x
  • 新:3倍
  • StringBuilder:3x

input

  • ((IEnumerable<char>)RandomString(STRLEN)).Take((int)ITERATIONS/2)

结果

  • Concat:1x
  • 新:7倍
  • StringBuilder:7倍

input

  • ((IEnumerable<char>)RandomString(STRLEN)) (这只是一个upcast)

结果

  • Concat:0 ms
  • 新:2000毫秒
  • StringBuilder:2000毫秒
  • Downcast:0毫秒

我在一个以.NET Framework 3.5为目标的英特尔i5 760上运行这个程序。

这里是一个更简洁的StringBuilder的答案:

 return charSequence.Aggregate(new StringBuilder(), (seed, c) => seed.Append(c)).ToString(); 

我使用Jeff Mercado使用的相同testing对此进行了计时,并且在相同的300个字符序列(32位版本构build版本)上,在1,000,000次迭代中比在更明确的情况下慢了1秒:

 static string StringBuilderChars(IEnumerable<char> charSequence) { var sb = new StringBuilder(); foreach (var c in charSequence) { sb.Append(c); } return sb.ToString(); } 

所以如果你是蓄电池的粉丝,那么你就去。

另一种可能是使用

 string.Join("", myEnumerable); 

我没有衡量performance。