将字符串列表转换为单个连接字符串的最快方法是什么?

10

我有一些LINQ代码,生成了一个字符串列表,就像这样:

var data = from a in someOtherList
           orderby a
           select FunctionThatReturnsString(a);

如何将字符串列表转换为一个大的连接字符串?假设数据具有以下条目:

"Some "
"resulting "
"data here."

我应该最终得到一个看起来像这样的字符串:

"Some resulting data here."

我该如何快速完成这个任务?我考虑了以下方案:

StringBuilder sb = new StringBuilder();
data.ToList().ForEach(s => sb.Append(s));
string result = sb.ToString();

但这似乎不太对。如果这是正确的解决方案,我该如何将其转换为扩展方法呢?

7个回答

22

这样怎么样:

public static string Concat(this IEnumerable<string> source) {
    StringBuilder sb = new StringBuilder();
    foreach(string s in source) {
        sb.Append(s);
    }
    return sb.ToString();
}

并且:

string s = data.Concat();

那么就不需要额外的 ToList() / ToArray() 步骤。


小改动:由于微软已经提供了一个Concat扩展方法,所以我不得不将其命名为ConcatString。 - jasonh
1
如果速度是问题,最好对列表进行两次遍历,第一次计算总长度,以便可以预先分配 StringBuilder。 - Steven Sudit
在这种情况下,您只需使用String.Concat。问题是,您正在处理一个IEnumerable<T>,您也不知道其大小(并且必须在某个地方存储项目引用以供重用)。 - Mehrdad Afshari
@Mehrdad:马克的代码也是这样。我把他的代码放进去,然后就遇到了编译器错误,而且智能感知(IntelliSense)把我带到了 MS 版本的元数据处,所以编译器肯定是试图使用 MS 版本。 - jasonh
1
@jasonh:我刚刚测试了一下,它按照我预期的方式工作。你的问题原因是其他方面引起的。Marc代码只需要一个参数,它将隐式转换为扩展方法,但MS版本需要两个参数(其中一个被隐式传递)。它们可以和谐共存。 - Mehrdad Afshari
显示剩余4条评论

16

你尝试过使用 String.Join 吗?如果你已经愿意承担 .ToList 调用的开销,那么可以改用 .ToArray() 并结合一个 String.Join 的调用。

var joined = String.Concat(someQuery.ToArray());

注意:我的解决方案可能不是最快的,因为它在数组中涉及了一些开销。我怀疑更像Marc那样去做会更快。但在大多数情况下,如果你只是想要快速、简单地在代码中完成它,我的方式可以工作。


2
有没有特别的原因不使用 string.Concat - Mehrdad Afshari
@Mehrdad,不,Join只是今天我脑海中浮现出来的第一个。 - JaredPar
在我的测试中,性能与Marc的解决方案不相上下(适用于各种字符串和集合长度),所以你得到了我的投票。 - LukeH

3

使用"Aggregate"的方法如下:

    List<string> strings = new List<string>() {"bob", "steve", "jane"};
    string result = strings.Aggregate((working, next) => working + next);
    Console.WriteLine(result);

注意:Aggregate是System.Linq命名空间中的扩展方法。

1
data.ToList().Aggregate(new StringBuilder(), (sb, s) => sb.Append(s)).ToString();

1

你可以使用这个语句:String.Join("",someOtherList);


你能再解释一下吗? - Dieter Meemken
也许不是最快的,但却是最简单的! - newman

0
根据JIT如何进行优化,string.Concat()或者Marc的StringBuilder方法都有可能更快。既然你在这里使用了Linq,我会假设性能并不是绝对的首要需求,在这种情况下,我会选择易于阅读的方法:
string.Concat(data.ToArray());

编辑:仅当数据是值类型的IEnumerable时,您需要将其转换为IEnumerable<object>:

string.Concat(data.Cast<object>().ToArray())

编辑2:我并不是说Linq很慢。我只是想说,我提到的这两种方法之间的速度差异应该极小,甚至可以忽略不计。

编辑3:JIT优化了String类上的几乎所有操作,因此单个调用string.Concat的内部运行时确实可能比使用StringBuilder更快。我不确定它是否如此,但您应该进行测试以确保。


LINQ 从何时开始等同于缓慢? - Mehrdad Afshari
为什么你会使用 data.Cast<object>() 而不是像 data.Select(x => x.ToString()) 这样的语句呢? - LukeH
字符串有一个成员string.Concat(object[] args),它很可能更有效地执行内部ToString操作。你需要将值类型数组(如int[])强制转换为object[]的唯一原因是无法隐式转换。 - Sam Harwell
Concat(object[])重载只是在内部调用标准的ToString方法。如果你自己对值类型执行ToString操作,而不是使用Cast进行装箱,那么你可以使用Concat(string[])重载。 - LukeH

0

替代方案:

>>> data = ['Some ', 'resulting ', 'data here.']
>>> s = ''.join(data)
>>> s
'Some resulting data here.'

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