IEnumerable的 字符串[复制]

问题描述 投票:121回答:6

这个问题在这里已有答案:

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

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

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

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

string allowedString = new string(inputString.Where(c => allowedChars.Contains(c)).ToArray());
c# .net string ienumerable
6个回答
133
投票

你可以使用String.Concat()

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

警告:这种方法会产生一些性能影响。 String.Concat不是字符的特殊情况集合,因此它表现得好像每个字符都被转换为字符串然后连接如in the documentationand it actually does)。当然,这为您提供了完成此任务的内置方法,但它可以做得更好。

我不认为在框架内有任何特殊情况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();
}

75
投票

编辑发布.Net Core 2.1

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

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

“新字符串”的1000000次迭代耗时1009ms。

“sb”的1000000次迭代耗时902ms。

简而言之,如果您使用.Net Core 2.1或更高版本,Concat就是王道。

有关详细信息,请参阅MS blog post


我已经把它作为another question的主题,但越来越多,这正成为这个问题的直接答案。

我做了一些性能测试3种简单的方法,将IEnumerable<char>转换为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();

在我的测试中,这在linked question中有详细介绍,对于1000000"Some reasonably small test data"迭代,我得到这样的结果,

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

“新字符串”的1000000次迭代耗时869ms。

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

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

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


19
投票

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

string.Concat(myEnumerable);

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

我的结果

  • 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上运行的。


10
投票

另一种可能性是使用

string.Join("", myEnumerable);

我没有衡量表现。


9
投票

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

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.