IEnumerable <char> to string

Con*_*ell 136 .net c# string ienumerable

我以前从来没有偶然发现过这个问题,但我现在已经感到惊讶,因为我找不到一个非常简单的方法来转换IEnumerable<char>为a string.

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

我认为这将是.NET框架内置的常用功能.有更简单的方法吗?

对于那些感兴趣的人,我想使用它的原因是使用LINQ来过滤字符串:

string allowedString = new string(inputString.Where(c => allowedChars.Contains(c)).ToArray());
Run Code Online (Sandbox Code Playgroud)

Jef*_*ado 142

你可以用String.Concat().

var allowedString = String.Concat(
    inputString.Where(c => allowedChars.Contains(c))
);
Run Code Online (Sandbox Code Playgroud)

警告:这种方法会产生一些性能影响. String.Concat不是字符的特殊情况集合,所以它执行就好像每个字符都被转换为字符串然后连接文档中提到(实际上它).当然,这为您提供了完成此任务的内置方法,但它可以做得更好.

我不认为框架内有任何特殊情况的char实现,所以你必须实现它.将字符附加到字符串构建器的简单循环非常简单,可以创建.


这是我在开发机器上采用的一些基准测试,看起来是正确的.

在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();
}
Run Code Online (Sandbox Code Playgroud)

  • ...它可能在内部使用StringBuilder,后者又在内部使用动态增长的char [],从中创建最终的`string`.与`new string(.ToArray())`似乎没什么区别. (7认同)
  • @Servy 我明白你在说什么。但是如果它确实使用了一个 `StringBuilder`,并且 _if_ 它最终在那个 `StringBuilder` 实例上使用了 `sb.ToString()`,那么 `sb.ToString()` 也可能会复制数据。因为一般来说,在调用 `.ToString()` 之后,`StringBuilder` 可以继续存在(并被改变)。但我同意他们可以采取阻止最终复制的技巧,例如,如果`StringBuilder` 有一个非公共方法`ToStringWithoutCopy`。 (2认同)

Jod*_*ell 79

编辑发布.Net Core 2.1

重复测试.Net Core 2.1的发布,我得到这样的结果

"Concat"的1000000次迭代耗时842ms.

"新字符串"的1000000次迭代耗时1009ms.

"sb"的1000000次迭代耗时902ms.

简而言之,如果您使用.Net Core 2.1或更高版本,Concat则为王.

有关详细信息,请参阅MS博客文章.


我已将此作为另一个问题的主题,但越来越多,这正在成为这个问题的直接答案.

我已经做了一些性能测试,将3种简单的方法转换IEnumerable<char>为a string,这些方法都是

新字符串

return new string(charSequence.ToArray());
Run Code Online (Sandbox Code Playgroud)

CONCAT

return string.Concat(charSequence)
Run Code Online (Sandbox Code Playgroud)

StringBuilder的

var sb = new StringBuilder();
foreach (var c in charSequence)
{
    sb.Append(c);
}

return sb.ToString();
Run Code Online (Sandbox Code Playgroud)

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

"Concat"的1000000次迭代耗时1597ms.

"新字符串"的1000000次迭代耗时869ms.

"StringBuilder"的1000000次迭代耗时748ms.

这告诉我,没有充分的理由使用string.Concat这项任务.如果你想要简单,请使用新的字符串方法,如果想要性能,请使用StringBuilder.

我会告诫我的断言,在实践中所有这些方法都运行良好,这可能都是过度优化.


Mik*_*keP 21

从.NET 4开始,许多字符串方法将IEnumerable作为参数.

string.Concat(myEnumerable);
Run Code Online (Sandbox Code Playgroud)


hBG*_*BGl 10

我的数据与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();
}
Run Code Online (Sandbox Code Playgroud)

我的结果

  • STRLEN = 31
  • ITERATIONS = 1000000

输入

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

结果

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

输入

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

结果

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

输入

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

结果

  • Concat:0毫秒
  • 新:2000毫秒
  • StringBuilder:2000毫秒
  • 垂头丧气:0毫秒

我是在针对.NET Framework 3.5的Intel i5 760上运行的.


nit*_*ycs 10

另一种可能性是使用

string.Join("", myEnumerable);
Run Code Online (Sandbox Code Playgroud)

我没有衡量表现.


Ada*_*ith 9

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

return charSequence.Aggregate(new StringBuilder(), (seed, c) => seed.Append(c)).ToString();
Run Code Online (Sandbox Code Playgroud)

我使用Jeff Mercado使用的相同测试进行计时,在相同的300字符序列(32位版本构建)上,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();
}
Run Code Online (Sandbox Code Playgroud)

所以,如果你是累积器的粉丝那么你去吧.