161

我以前从未偶然发现过这种情况,但现在我发现并很惊讶我找不到一种非常简单的方法将 an 转换IEnumerable<char>string.

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

我原以为这将是 .NET 框架中内置的通用功能。有没有更简单的方法来做到这一点?

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

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

6 回答 6

170

您可以使用String.Concat().

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

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

我认为框架内没有任何特殊情况char的实现,因此您必须实现它。将字符附加到字符串生成器的简单循环很容易创建。


这是我在开发机器上进行的一些基准测试,看起来差不多。

在 32 位版本构建上,对 300 个字符序列进行 1000000 次迭代:

ToArrayString: 00:00:03.1695463
连接:00:00:07.2518054
字符串生成器字符:00:00:03.1335455
字符串生成器字符串: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();
}
于 2012-07-25T16:19:34.370 回答
88

针对 .Net Core 2.1 的发布进行了编辑

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

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

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

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

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

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


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

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

新字符串

return new string(charSequence.ToArray());

康卡特

return string.Concat(charSequence)

字符串生成器

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

return sb.ToString();

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

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

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

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

这向我表明,没有充分的理由使用string.Concat此任务。如果您想要简单,请使用新的字符串方法,如果想要性能,请使用StringBuilder

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

于 2013-02-11T12:37:28.853 回答
22

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

string.Concat(myEnumerable);
于 2012-07-25T16:19:38.350 回答
11

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

因此,如果您是累加器的粉丝,那么您就去吧。

于 2014-10-24T04:31:14.653 回答
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
  • 迭代次数 = 1000000

输入

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

结果

  • 连续:1x
  • 新:3x
  • 字符串生成器:3x

输入

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

结果

  • 连续:1x
  • 新:7x
  • 字符串生成器:7x

输入

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

结果

  • 连续:0 毫秒
  • 新:2000 毫秒
  • 字符串生成器:2000 毫秒
  • 向下转换:0 毫秒

我在面向 .NET Framework 3.5 的 Intel i5 760 上运行它。

于 2013-07-03T22:07:07.007 回答
10

Another possibility is using

string.Join("", myEnumerable);

I did not measure the performance.

于 2014-08-21T13:21:22.857 回答