最有效的连接字符串的方法

时间:2011-05-01 20:46:52

标签: c# performance string

我需要连接很多字符串并在其中任何一个之间加上逗号。 我有一个字符串列表

"123123123213"
"1232113213213"
"123213123"

我希望得到

"123123123213,1232113213213,123213123"

我想知道实现这一目标的最佳途径是什么。

我可以这样做:

private List<string> stringList = new List<string> { 
    // a lot of strings in here
    "1234567890", "34343434", "4343434" }; 

string outcome = string.Join(",", stringList.ToArray());

或者也许:

StringBuilder builder = new StringBuilder();
stringList.ForEach(val => {
    builder.Append(val);
    builder.Append(",");
});

string outcome = builder.ToString();

哪种方式更好?你知道连接字符串的更好方法吗?

11 个答案:

答案 0 :(得分:6)

@Ekkehard所述,请使用string.Join

但是,您不需要ToArray(),因为string.Join的{​​{1}}超载。

IEnumerable<string>

修改

正如@Kobi所说,这只适用于C#4.0。在3.5我会这样做。

List<string> stringList = new List<string> 
    { "1234567890", "34343434", "4343434" }; 

string outcome = string.Join(",", stringList);

答案 1 :(得分:5)

您应该使用string.Join(),因为:

a)它更具可读性,易维护性和易于使用。

b)它已经在内部使用了StringBuilder,所以它非常有效(你可以使用Reflector确认自己)。

修改:

string.Join()使用StringBuilder作为IEnumerable<T>输入的一般情况。如果你已经拥有一个数组,那么它会使用一些巫术魔法(包括FastAllocateString()UnSafeCharBuffer)来更快。

答案 2 :(得分:1)

使用Join,因为它不会添加尾随“,”。

答案 3 :(得分:1)

this page上有一个基准测试似乎表明string.Join在很多次迭代中对小数组的效果优于StringBuilder。您也应该对较大的阵列进行基准测试。正如我发布的那样,我看到BrokenGlass回答StringBuilderstring.Join内部使用,所以你可以预期它会更快。

答案 4 :(得分:1)

您的第二个解决方案最后会额外添加,。看看Eric Lippert`s blog entry

我建议您修复第二个解决方案。一个StringBuilder肯定会更快,因为你避免将列表内容复制到一个新数组。

StringBuilder builder = new StringBuilder();
string separator = "";
stringList.ForEach(
    val =>
    {
        builder.Append(separator).Append(val);
        separator = ",";
    });
string outcome = builder.ToString();

答案 5 :(得分:0)

StringBuilder是一种非常有效的方法,建议在这里使用。

答案 6 :(得分:0)

我尝试使用StrignBuilder的这个特殊实现比String.Join更快。 不仅仅是String.Join是一个MEMORY HOG。 我试用了20000000个字符串,当我的实现完成时,String.Join总是给OutOfMemory。 在你的机器上如果你的内存少于8Gb,它甚至可以在更少的字符串上。 评论其中一个要测试的实现。 除非您使用固定的string []数组,否则这是正确的。 String.Join在那里很好。

   public static void Main(string[] Args)
    {
        Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

          List<string> strings = new List<string>() {};
        for (double d = 0; d < 8000000; d++) {
            strings.Add(d.ToString());
        }

        TimeSpan upTime;
        TimeSpan newupTime;
        using (var pc = new PerformanceCounter("System", "System Up Time"))
        {
            StringBuilder sb = new StringBuilder(strings.Count);
            int i;

            pc.NextValue();    //The first call returns 0, so call this twice
            upTime = TimeSpan.FromSeconds(pc.NextValue());

            for (i = 0; i < strings.Count - 1; i++)
            {
                sb.Append(strings[i]);
                sb.Append(",");
            }
            sb.Append(strings[i]);

            newupTime = TimeSpan.FromSeconds(pc.NextValue());
            sb = null;
            Console.WriteLine("SB " + (newupTime - upTime).TotalMilliseconds);
        }

        using (var pc = new PerformanceCounter("System", "System Up Time"))
        {

            pc.NextValue();
            upTime = TimeSpan.FromSeconds(pc.NextValue());

            string s = string.Join(",", strings);

            newupTime = TimeSpan.FromSeconds(pc.NextValue());
            Console.WriteLine("JOIN " + (newupTime - upTime).TotalMilliseconds);
        }


    }
SB 406
JOIN 484

答案 7 :(得分:0)

根据以下测试,我在大型阵列上做了加速快了3倍

Text.txt文件包含38400行的值"aaaaaaaaaaaaaaaaaaa"

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      var strings = File.ReadAllLines("Text.txt");

      Stopwatch sw;

      StringBuilder sb = new StringBuilder();

      sw = Stopwatch.StartNew();
      for (int i = 0; i < strings.Length; i++)
      {
        sb.AppendLine(strings[i]);
      }
      sw.Stop();
      TimeSpan sbTime = sw.Elapsed;

      sw = Stopwatch.StartNew();
     var output = string.Join(",", strings);
     sw.Stop();

     TimeSpan joinTime = sw.Elapsed;   

    }
  }
}

输出:

00:00:00.0098754
00:00:00.0032922

答案 8 :(得分:0)

如果要加入固定数量的字符串,

String.Join是最快的。更深层次的原因是String.Join循环遍历数组并分配具有正确大小的最终字符串缓冲区,因为它在第一遍中添加所有字符串的字符串长度。当您使用StringBuilder及其容量时,您可以获得类似的结果。黄金法则是以两次循环数组为代价来节省内存分配。哪种方法更快取决于列表中有多少项以及resultint字符串的大小。

此致,   Alois Kraus

答案 9 :(得分:0)

测试代码:

public static void Performance(Action fn)
{
    var timer = new Stopwatch();
    timer.Start();

    for (var i = 0; i < 10000000; ++i)
    {
        fn();
    }

    timer.Stop();

    Console.WriteLine("{0} Time: {1}ms ({2})", fn.ToString(), timer.ElapsedMilliseconds, timer.ElapsedTicks);
}

static void Main(string[] args)
{
    var stringList = new List<string>() {
        "123123123213",
        "1232113213213",
        "123213123"
    };

    string outcome = String.Empty;
    Performance(() =>
    {
        outcome = string.Join(",", stringList);
    });

    Console.WriteLine(outcome);

    Performance(() =>
    {
        StringBuilder builder = new StringBuilder();
        stringList.ForEach
            (
                val =>
                {
                    builder.Append(val);
                    builder.Append(",");
                }
            );
        outcome = builder.ToString();
        outcome = outcome.Substring(0, outcome.Length - 1);
    });

    Console.WriteLine(outcome);

    Console.ReadKey();

}

结果1. String.Join - 2. StringBuilder + SubString####ms (ticks)

result

在这种情况下,String.Join速度更快,但如果您可以使用尾随,,那么

string builder

StringBuilder稍快一些(尾随,)。

答案 10 :(得分:0)

如果一个人想要冷静并在重燃料上运行,请使用Aggregate

List<string> stringList = new List<string> { "1234567890", "34343434", "4343434" };

Console.WriteLine( stringList.Aggregate( ( current, next ) => string.Format( "{0}, {1}", current, next ) ) );

// Outputs:   1234567890, 34343434, 4343434