连接字符串的最有效方法

7
我需要将许多字符串串在一起,并在它们之间放置逗号。我有一个字符串列表。
"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();

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


2
相关或可能重复:https://dev59.com/RHA75IYBdhLWcg3wy8Ui - BrunoLM
为什么不亲自测试一下性能呢? - Jan
你没有说明什么是最好的。我已经在你的问题中添加了performance标签。 - Shimmy Weitzhandler
11个回答

6

正如@Ekkehard所说,使用string.Join

但是,您不需要ToArray(),因为string.Join有一个重载方法可以接受IEnumerable<string>

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

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

编辑

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

var s = new StringBuilder(stringList.Count * 8);
foreach (var item in stringList)
{
   s.Append(item);
   s.Append(',');
}
s.Length -= 1;
string outcome = stringList.ToList();

3
请注意,这是在 .Net 4 中新增的功能,3.5 仍需要使用数组。 - Kobi

5
你应该使用 string.Join(),因为:
a) 它更易读、易于维护和易于理解。
b) 它已经在内部使用了一个 StringBuilder,所以它非常高效(你可以使用 Reflector 自己确认)。
编辑: string.Join() 对于一般的 IEnumerable<T> 输入使用 StringBuilder。另一方面,如果你已经有了一个数组,则它使用一些神秘的魔法(包括 FastAllocateString()UnSafeCharBuffer)来提高速度。

FYI,string.Join(string, string[]) 不使用 StringBuilder,而是使用 UnSafeCharBuffer - svick
@svick:是的,我在观察后也正在编辑,这确实是巫术魔法。;-) - BrokenGlass

1

你的第二个解决方案在末尾添加了一个额外的,。请查看Eric Lippert的博客文章

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

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

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

1

这个页面上有一个基准测试,似乎表明在很多迭代中,string.JoinStringBuilder在小数组上的性能更好。你应该为更大的数组进行基准测试。当我发布这篇文章时,我看到BrokenGlass回答说,在string.Join内部使用了StringBuilder,所以你可以期望它更快吧。


0

我尝试使用StringBuilder的临时实现比String.Join更快。 而且,String.Join占用内存太多了。 我尝试使用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

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

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####毫秒(滴答)

result

在这种情况下,String.Join更快,但是如果您可以接受尾随的,,那么

string builder

StringBuilder稍微快一些(带有末尾的,)。


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

0

使用StringBuilder是一种非常高效的方式,这里强烈推荐。


除了 string.Join() 可以更有效(至少在你给它 string[] 的情况下,否则它会使用 StringBuilder 本身)。 - svick
svick,你给一个比你说得更聪明的人打了个负一分。而且问者需要的是字符串列表,不是数组。 - Marino Šimić
@Marino,使用StringBuilder比使用string.Join()更聪明吗?后者更清晰,更少出错(您不必编写自己的代码),并且可能更快。 - svick
哎呀,那只是一个替代方案。 - Kevin Hsu
使用string.join,您必须将列表转换为数组。这可能不是最有效的方法,特别是如果您有很多小字符串。 - Kevin Hsu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接