【问题标题】:C# big string array to stringC# 大字符串数组到字符串
【发布时间】:2016-03-05 21:03:03
【问题描述】:

我有一个包含大约 20,000,000 个值的字符串数组。 我需要将其转换为字符串

我试过了:

    string data = "";
    foreach (var i in tm)
    {
        data = data + i;
    }

但是时间太长了

有人知道更快的方法吗?

【问题讨论】:

  • 你为什么需要一个这么大的string
  • 我正在为学校制作拉链
  • 性能很差,因为data = data + iShlemiel the painter's algorithm
  • 我不确定你需要为你的拉链做些什么,但必须有一种方法可以在不创建巨大字符串的情况下完成它。
  • 对于如此大的串联,您需要查看其他选项,例如流式传输到磁盘

标签: c# arrays string performance


【解决方案1】:

试试StringBuilder:

StringBuilder sb = new StringBuilder();
foreach (var i in tm)
{
    sb.Append(i);
}

要获得结果String,请使用ToString()

string result = sb.ToString();

【讨论】:

  • 谢谢,但我收到以下错误:mscorlib.dll 中出现“System.OutOfMemoryException”类型的未处理异常
  • @SerhatReis 请注意,即使在 x64 环境中 there is 2 GB limit
  • @Filburt 您提供的链接上的下一个(也是最近的)答案指出,从 .NET 4.5 开始,2GB 限制不适用于 x64 ...
  • @DrewJordan 限制仍然适用,但可以禁用。
  • @DrewJordan 2GB 限制用于对象。在最新的 x64 框架中,它是宽松的,但字符串仍然只能容纳最多 int.MaxValue 个字符。字符串在内部使用 int 作为长度,因此它们的长度不能超过 2^31-1 个字符。
【解决方案2】:

答案将取决于输出字符串的大小以及可用和可用的内存量。字符串长度的硬限制似乎是 2^31-1 (int.MaxValue) 个字符,占用刚刚超过 4GB 的内存。是否可以实际分配取决于您的框架版本等。如果您要产生更大的输出,那么无论如何您都不能将其放入单个字符串中。

您已经发现,幼稚的连接将会非常缓慢。问题是每次通过循环都会创建一个新字符串,然后在下一次迭代中立即丢弃它。这将很快填满内存,迫使垃圾收集器加班寻找旧字符串以清除内存,更不用说内存碎片的数量以及现代程序员不太关注的所有东西了。

StringBuiler,是一个合理的解决方案。在内部,它分配字符块,然后在最后使用指针和内存副本将它们拼接在一起。这样可以省去很多麻烦,而且速度很快。

至于String.Join...it uses a StringBuilderString.Concat 也是如此,尽管不插入分隔符肯定会更快。

为简单起见,我将使用 String.Concat 并完成它。

但我并不太简单。

这是一个使用 LINQ 的未经测试且可能非常缓慢的答案。当我有时间时,我会对其进行测试,看看它的表现如何,但现在:

string result = new String(lines.SelectMany(l => (IEnumerable<char>)l).ToArray());

显然这里有一个潜在的溢出,因为ToArray 调用可能会创建一个比String 构造函数可以处理的更大的数组。试试看是否和String.Concat一样快。

【讨论】:

    【解决方案3】:

    所以你可以在 LINQ 中这样做,就像这样。

    string data = tm.Aggregate("", (current, i) => current + i);
    

    或者你可以使用 string.Join 函数

    string data = string.Join("", tm);
    

    【讨论】:

    • 你拥有的Aggregate 基本上是一样的,并且会有同样可怕的表现。 Join 可以,但string.Concat 更有意义。
    • 我真的很好奇每个解决方案的指标。我自己对这种方式的 linq 期望不高,并且可能会计算每个指标来满足我的好奇心。
    【解决方案4】:

    现在无法检查,但我很好奇这个选项的效果:

    var data = String.Join(string.Empty, tm);
    

    Join 是否已优化并忽略与 String.Empty 的串联 a?

    【讨论】:

    • Join 似乎没有为空分隔符提供任何特殊津贴。他们有针对这种情况的Concat 方法,所以我猜他们认为没有必要在Join 中对其进行测试。
    【解决方案5】:

    不幸的是,对于这种大数据,基于内存的方法将失败,这对 GC 来说将是一个真正令人头疼的问题。为此操作创建一个文件并将每个字符串放入其中。像这样:

    using (StreamWriter sw = new StreamWriter("some_file_to_write.txt")){
        for (int i=0; i<tm.Length;i++)
            sw.Write(tm[i]);
    }
    

    在这种要求性能的方法上尽量避免使用“var”。 更正:“var”不影响性能。 “动态”可以。

    【讨论】:

    • 为什么不使用var?它在编译时解决,因此对性能的影响应该为零。
    • @Corey 感谢您的提问。将vardynamic 混合在一起是我的错误。我已经更正了。
    • 一切都好。我想这要么是一个错误,要么是我不知道的事情。实际上希望是后者:)
    猜你喜欢
    • 2013-04-15
    • 2014-10-24
    • 1970-01-01
    • 2020-08-23
    • 1970-01-01
    • 2013-06-19
    • 2015-02-13
    • 2014-04-24
    • 1970-01-01
    相关资源
    最近更新 更多