使用LINQ将List<string>中的所有字符串连接起来

672

是否有一种简单的LINQ表达式,可以使用分隔符将我整个List<string>集合中的所有项连接成一个string

如果集合是自定义对象而不是string呢?想象一下我需要在object.Name上进行连接。


45
为什么要用 LINQ 而不是 string.Join()? - Alan
16
string.Join更好,但我认为LINQ让你的代码更有趣,这可能就是原因! - Ali Ersöz
22
String.Join更好,因为它使用了StringBuilder并避免了反复拼接带来的O(n^2)性能问题。 - Kennet Belenky
1
使用LINQ存在性能问题吗? - PreguntonCojoneroCabrón
12个回答

1235
string result = String.Join(delimiter, list);

足够。


104
我完全支持使用LINQ解决方案,但这种方法比LINQ和Aggregate()方法更高效。 - andleer
22
更加清晰!对我非常有效! string.Join(", ", accs.Select(x => x.AccountID).ToArray()), - m4tt1mus
36
@KonstantinSalavatov 在 OP 澄清必须使用 LINQ 之前,我已经发布了我的答案。对于任何在 Google 上寻找“不一定需要使用 LINQ”解决方案的人来说,它仍然是完全有效的。在这种情况下认为这个答案“没有用处”是不公平的。 - Sedat Kapanoglu
7
这也可用于除 List<String> 以外的其他事物,并将调用 ToString() 方法。 - Kian
2
@alansiqueira27 嗯,List<string> 永远不会是一个查询到数据库的操作。这是完全不同的问题,但你总是可以调用 .ToList() 将查询结果合并后再进行操作。 - Sedat Kapanoglu
显示剩余4条评论

561

警告 - 严重的性能问题

虽然这个答案可以得到所需的结果,但与其他答案相比,它的性能较差。在决定是否使用它时要非常小心。


使用LINQ,应该会起作用;

string delimiter = ",";
List<string> items = new List<string>() { "foo", "boo", "john", "doe" };
Console.WriteLine(items.Aggregate((i, j) => i + delimiter + j));

类描述:

public class Foo
{
    public string Boo { get; set; }
}

使用方法:

class Program
{
    static void Main(string[] args)
    {
        string delimiter = ",";
        List<Foo> items = new List<Foo>() { new Foo { Boo = "ABC" }, new Foo { Boo = "DEF" },
            new Foo { Boo = "GHI" }, new Foo { Boo = "JKL" } };

        Console.WriteLine(items.Aggregate((i, j) => new Foo{Boo = (i.Boo + delimiter + j.Boo)}).Boo);
        Console.ReadKey();

    }
}

这是我的最佳作品 :)

items.Select(i => i.Boo).Aggregate((i, j) => i + delimiter + j)

49
O(n^2) 时间又来袭。 - Kennet Belenky
2
如果您看不到Aggregate方法,则需要添加using System.Linq;。 - Cédric Guillemette
7
问题在于上述的 LinQ 方法无法处理空列表或只包含一个元素的列表。 - Alexander
13
为什么不直接使用 string.join?请接受 Sedat 的答案,以免有人匆忙选择这个解决方案,而 Sedat 的方案更好。 - Skystrider
8
不要使用这个。即使在一个简单的字符串集合上,这个解决方案也会立即降低应用程序性能。请使用Sedat的答案和string.Join! - Bryan Boettcher
显示剩余4条评论

148

注意:此答案不使用LINQ来生成连接字符串。使用LINQ将可枚举对象转换为分隔字符串可能会导致严重的性能问题。

现代.NET(自.NET 4开始)

这适用于数组、列表或任何实现IEnumerable接口的类型:

string.Join(delimiter, enumerable);

这是针对自定义对象的可枚举性:

string.Join(delimiter, enumerable.Select(i => i.Boo));

旧版 .NET(.NET 4 之前)

以下代码适用于字符串数组:

string.Join(delimiter, array);

这是一个 List<string>:

string.Join(delimiter, list.ToArray());

而这是针对自定义对象列表的:

string.Join(delimiter, list.Select(i => i.Boo).ToArray());

30
String.Join有一个重载方法可以接收IEnumerable参数,因此你不需要使用ToArray()方法。 - arolson101
12
请记住,IEnumerable重载仅存在于4.0或更高版本。如果您使用的是旧版本,则仍需要使用ToArray()。 - Rakuen42
2
啊!那个最后的重载正是我在寻找的。我知道一定有一种方法可以提取特定的属性。 :) - Mike Devenney

60
using System.Linq;

public class Person
{
  string FirstName { get; set; }
  string LastName { get; set; }
}

List<Person> persons = new List<Person>();

string listOfPersons = string.Join(",", persons.Select(p => p.FirstName));

27

好问题。我一直在使用

List<string> myStrings = new List<string>{ "ours", "mine", "yours"};
string joinedString = string.Join(", ", myStrings.ToArray());

这不是 LINQ,但它可以工作。


为什么你必须调用.ToArray()方法? - Ε Г И І И О
3
因为在2009年的那个糟糕的时代,string.Join方法没有接受IEnumerable参数的扩展。 - Jacob Proffitt

10

你可以简单地使用:

List<string> items = new List<string>() { "foo", "boo", "john", "doe" };

Console.WriteLine(string.Join(",", items));

愉快地编码吧!


8

我认为如果你将逻辑定义在扩展方法中,代码会更易读:

public static class EnumerableExtensions { 
  public static string Join<T>(this IEnumerable<T> self, string separator) {  
    return String.Join(separator, self.Select(e => e.ToString()).ToArray()); 
  } 
} 

public class Person {  
  public string FirstName { get; set; }  
  public string LastName { get; set; }  
  public override string ToString() {
    return string.Format("{0} {1}", FirstName, LastName);
  }
}  

// ...

List<Person> people = new List<Person>();
// ...
string fullNames = people.Join(", ");
string lastNames = people.Select(p => p.LastName).Join(", ");

7
List<string> strings = new List<string>() { "ABC", "DEF", "GHI" };
string s = strings.Aggregate((a, b) => a + ',' + b);

4

我已经使用LINQ完成了这个操作:

var oCSP = (from P in db.Products select new { P.ProductName });

string joinedString = string.Join(",", oCSP.Select(p => p.ProductName));

2
这个回答旨在扩展和改进一些基于LINQ的解决方案的提及。这并不是一个“好”的解决方法的例子,只要符合您的需求就使用string.Join建议即可。

背景

这个回答是由问题的第二部分(通用方法)以及一些表达对LINQ的深刻喜爱的评论所促成的。

鉴于没有符合所有这些要求的答案,我提出了一种基于LINQ的实现,以线性时间运行,适用于任意长度的枚举,并支持将元素通用转换为字符串。
所以,只能使用LINQ吗?好的。
static string Serialize<T>(IEnumerable<T> enumerable, char delim, Func<T, string> toString)
{
    return enumerable.Aggregate(
        new StringBuilder(),
        (sb, t) => sb.Append(toString(t)).Append(delim),
        sb =>
        {
            if (sb.Length > 0)
            {
                sb.Length--;
            }

            return sb.ToString();
        });
}

这种实现比许多其他替代方案更复杂,主要是因为我们需要在自己的代码中管理分隔符(分隔符)的边界条件。
它应该在线性时间内运行,最多遍历元素两次。
一次用于生成首先要附加的所有字符串,零到一次用于在最终ToString调用期间生成最终结果。这是因为后者可能只能返回刚好足够包含从一开始附加的所有字符串的缓冲区,或者必须重新生成整个内容(不太可能),或者介于两者之间。有关更多信息,请参见例如SO上的What is the Complexity of the StringBuilder.ToString()
最后的话
如果适合您的需求,请使用string.Joinas suggested,在需要先处理序列时添加Select
本答案的主要目的是说明使用LINQ可以保持性能。结果可能过于冗长,不推荐使用。

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