从IList <string>或IEnumerable <string>创build逗号分隔的列表

IList<string>IEnumerable<string>创build一个逗号分隔的string值列表的最简洁的方法是什么?

String.Join(...)string[]操作,因此当IList<string>IEnumerable<string>不能轻易转换为string数组时,可能会很麻烦。

.NET 4+

 IList<string> strings = new List<string>{"1","2","testing"}; string joined = string.Join(",", strings); 

Detail&Pre .Net 4.0解决scheme

IEnumerable<string>可以容易地用LINQ(.NET 3.5)转换成一个string数组:

 IEnumerable<string> strings = ...; string[] array = strings.ToArray(); 

如果您需要:编写等效的帮助程序方法很容易:

 public static T[] ToArray(IEnumerable<T> source) { return new List<T>(source).ToArray(); } 

然后像这样调用它:

 IEnumerable<string> strings = ...; string[] array = Helpers.ToArray(strings); 

然后你可以调用string.Join 。 当然,你不必使用辅助方法:

 // C# 3 and .NET 3.5 way: string joined = string.Join(",", strings.ToArray()); // C# 2 and .NET 2.0 way: string joined = string.Join(",", new List<string>(strings).ToArray()); 

后者虽然有点满口:)

这可能是最简单的方法,而且性能也很高 – 还有其他问题,包括(但不限于) 这个 。

从.NET 4.0开始, string.Join有更多的重载,所以你可以写下:

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

更简单:)

仅供参考,.NET 4.0版本的string.Join()有一些额外的重载 ,可以用IEnumerable而不是数组,包括一个可以处理任何types的T

 public static string Join(string separator, IEnumerable<string> values) public static string Join<T>(string separator, IEnumerable<T> values) 

我能看到的最简单的方法是使用LINQ Aggregate方法:

 string commaSeparatedList = input.Aggregate((a, x) => a + ", " + x) 

我认为创build逗号分隔的string值列表的最简单的方法是:

 string.Join<string>(",", stringEnumerable); 

这是一个完整的例子:

 IEnumerable<string> stringEnumerable= new List<string>(); stringList.Add("Comma"); stringList.Add("Separated"); string.Join<string>(",", stringEnumerable); 

没有必要做一个帮手function,这是内置到.NET 4.0及以上。

这是另一种扩展方法:

  public static string Join(this IEnumerable<string> source, string separator) { return string.Join(separator, source); } 

东西有点难看,但它的工作原理:

 string divisionsCSV = String.Join(",", ((List<IDivisionView>)divisions).ConvertAll<string>(d => d.DivisionID.ToString("b")).ToArray()); 

给你一个CSV列表后,你给它的转换器(在这种情况下,d => d.DivisionID.ToString(“b”))。

哈克但是作品 – 也许可以做成扩展方法?

这是我做的方式,用我用其他语言做的方式:

 private string ToStringList<T>(IEnumerable<T> list, string delimiter) { var sb = new StringBuilder(); string separator = String.Empty; foreach (T value in list) { sb.Append(separator).Append(value); separator = delimiter; } return sb.ToString(); } 

到这个讨论稍迟,但这是我的贡献。 我有一个IList<Guid> OrderIds被转换为一个CSVstring,但以下是通用的,并与其他types未修改工作:

 string csv = OrderIds.Aggregate(new StringBuilder(), (sb, v) => sb.Append(v).Append(","), sb => {if (0 < sb.Length) sb.Length--; return sb.ToString();}); 

简短而亲切,使用StringBuilder构造新的string,将StringBuilder长度缩小一个以除去最后一个逗号并返回CSVstring。

我更新了这个使用多个Append()来添加string+逗号。 从James的反馈中,我使用了Reflector来看看StringBuilder.AppendFormat() 。 结果AppendFormat()使用一个StringBuilder来构造格式化string,这使得在这个上下文中效率低于只使用多个Appends()

具体需要什么时候我们应该围绕',由前:

  string[] arr = { "jj", "laa", "123" }; List<string> myList = arr.ToList(); // 'jj', 'laa', '123' Console.WriteLine(string.Join(", ", myList.ConvertAll(m => string.Format("'{0}'", m)).ToArray())); 

比赛的成绩是“循环,join,后退”。 实际上“enumerable和manual move next”是一样的好(考虑stddev)。

 BenchmarkDotNet=v0.10.5, OS=Windows 10.0.14393 Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4 Frequency=3233539 Hz, Resolution=309.2587 ns, Timer=TSC [Host] : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0 Clr : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0 Core : .NET Core 4.6.25009.03, 64bit RyuJIT Method | Job | Runtime | Mean | Error | StdDev | Min | Max | Median | Rank | Gen 0 | Allocated | ---------------------- |----- |-------- |---------:|----------:|----------:|---------:|---------:|---------:|-----:|-------:|----------:| StringJoin | Clr | Clr | 28.24 us | 0.4381 us | 0.3659 us | 27.68 us | 29.10 us | 28.21 us | 8 | 4.9969 | 16.3 kB | SeparatorSubstitution | Clr | Clr | 17.90 us | 0.2900 us | 0.2712 us | 17.55 us | 18.37 us | 17.80 us | 6 | 4.9296 | 16.27 kB | SeparatorStepBack | Clr | Clr | 16.81 us | 0.1289 us | 0.1206 us | 16.64 us | 17.05 us | 16.81 us | 2 | 4.9459 | 16.27 kB | Enumerable | Clr | Clr | 17.27 us | 0.0736 us | 0.0615 us | 17.17 us | 17.36 us | 17.29 us | 4 | 4.9377 | 16.27 kB | StringJoin | Core | Core | 27.51 us | 0.5340 us | 0.4995 us | 26.80 us | 28.25 us | 27.51 us | 7 | 5.0296 | 16.26 kB | SeparatorSubstitution | Core | Core | 17.37 us | 0.1664 us | 0.1557 us | 17.15 us | 17.68 us | 17.39 us | 5 | 4.9622 | 16.22 kB | SeparatorStepBack | Core | Core | 15.65 us | 0.1545 us | 0.1290 us | 15.45 us | 15.82 us | 15.66 us | 1 | 4.9622 | 16.22 kB | Enumerable | Core | Core | 17.00 us | 0.0905 us | 0.0654 us | 16.93 us | 17.12 us | 16.98 us | 3 | 4.9622 | 16.22 kB | 

码:

 public class BenchmarkStringUnion { List<string> testData = new List<string>(); public BenchmarkStringUnion() { for(int i=0;i<1000;i++) { testData.Add(i.ToString()); } } [Benchmark] public string StringJoin() { var text = string.Join<string>(",", testData); return text; } [Benchmark] public string SeparatorSubstitution() { var sb = new StringBuilder(); var separator = String.Empty; foreach (var value in testData) { sb.Append(separator).Append(value); separator = ","; } return sb.ToString(); } [Benchmark] public string SeparatorStepBack() { var sb = new StringBuilder(); foreach (var item in testData) sb.Append(item).Append(','); if (sb.Length>=1) sb.Length--; return sb.ToString(); } [Benchmark] public string Enumerable() { var sb = new StringBuilder(); var e = testData.GetEnumerator(); bool moveNext = e.MoveNext(); while (moveNext) { sb.Append(e.Current); moveNext = e.MoveNext(); if (moveNext) sb.Append(","); } return sb.ToString(); } } 

https://github.com/dotnet/BenchmarkDotNet被使用;

我们有一个实用的function,像这样:

 public static string Join<T>( string delimiter, IEnumerable<T> collection, Func<T, string> convert ) { return string.Join( delimiter, collection.Select( convert ).ToArray() ); } 

哪些可以用于轻松地连接大量的集合:

 int[] ids = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233}; string csv = StringUtility.Join(",", ids, i => i.ToString() ); 

请注意,我们有lambda之前的集合参数,因为intellisense然后拿起集合types。

如果你已经有了一个string枚举,你需要做的就是ToArray:

 string csv = string.Join( ",", myStrings.ToArray() ); 

我刚才解决了这个问题之前发生的这篇文章。 我的解决scheme如下所示:

  private static string GetSeparator<T>(IList<T> list, T item) { return (list.IndexOf(item) == list.Count - 1) ? "" : ", "; } 

被调用如:

 List<thing> myThings; string tidyString; foreach (var thing in myThings) { tidyString += string.format("Thing {0} is a {1}", thing.id, thing.name) + GetSeparator(myThings, thing); } 

我也可以很容易地expression出来,也可以更有效率:

 string.Join(“,”, myThings.Select(t => string.format(“Thing {0} is a {1}”, t.id, t.name)); 

因为我在search时join了一个对象列表的特定属性(而不是它的ToString()),所以这里是对接受的答案的补充:

 var commaDelimited = string.Join(",", students.Where(i => i.Category == studentCategory) .Select(i => i.FirstName)); 

您可以使用ToArray将IList转换为数组,然后在数组上运行string.join命令。

 Dim strs As New List(Of String) Dim arr As Array arr = strs.ToArray 

可以使用.NET 3.5中的Linq扩展将它们轻松转换为数组。

  var stringArray = stringList.ToArray(); 

在使用其他人列出的方法之一将其转换为数组之后,您也可以使用类似于以下内容的内容:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Net; using System.Configuration; namespace ConsoleApplication { class Program { static void Main(string[] args) { CommaDelimitedStringCollection commaStr = new CommaDelimitedStringCollection(); string[] itemList = { "Test1", "Test2", "Test3" }; commaStr.AddRange(itemList); Console.WriteLine(commaStr.ToString()); //Outputs Test1,Test2,Test3 Console.ReadLine(); } } } 

编辑: 这是另一个例子

我的答案就像上面的聚合解决scheme,但应该更less的调用堆栈,因为没有明确的委托调用:

 public static string ToCommaDelimitedString<T>(this IEnumerable<T> items) { StringBuilder sb = new StringBuilder(); foreach (var item in items) { sb.Append(item.ToString()); sb.Append(','); } if (sb.Length >= 1) sb.Length--; return sb.ToString(); } 

当然,可以将签名扩展为与分隔符无关。 我真的不是sb.Remove()调用的粉丝,我想重构它是一个直接的IEnumerable while循环,并使用MoveNext()来确定是否写一个逗号。 如果我碰到这个问题,我会绕过这个解决scheme。


这是我最初想要的:

 public static string ToDelimitedString<T>(this IEnumerable<T> source, string delimiter, Func<T, string> converter) { StringBuilder sb = new StringBuilder(); var en = source.GetEnumerator(); bool notdone = en.MoveNext(); while (notdone) { sb.Append(converter(en.Current)); notdone = en.MoveNext(); if (notdone) sb.Append(delimiter); } return sb.ToString(); } 

不需要临时数组或列表存储,也不需要StringBuilder Remove()Length-- hack。

在我的框架库中,我对这个方法签名做了一些修改,包括delimiterconverter参数的每个组合,分别使用","x.ToString()作为默认值。

希望这是最简单的方法

  string Commaseplist; string[] itemList = { "Test1", "Test2", "Test3" }; Commaseplist = string.join(",",itemList); Console.WriteLine(Commaseplist); //Outputs Test1,Test2,Test3 

当我search一个好的C#方法来joinstring时,我讨论了这个讨论,就像使用MySql方法CONCAT_WS() 。 此方法不同于string.Join()方法,因为如果string为NULL或空,它不会添加分隔符。

CONCAT_WS(',',tbl.Lastname,tbl.Firstname)

如果firstname是空的,将只返回Lastname

string.Join(“,”,strLastname,strFirstname)

将返回strLastname + ", "在相同的情况下。

想要第一个行为,我写了下面的方法:

  public static string JoinStringsIfNotNullOrEmpty(string strSeparator, string strA, string strB, string strC = "") { return JoinStringsIfNotNullOrEmpty(strSeparator, new[] {strA, strB, strC}); } public static string JoinStringsIfNotNullOrEmpty(string strSeparator, string[] arrayStrings) { if (strSeparator == null) strSeparator = ""; if (arrayStrings == null) return ""; string strRetVal = arrayStrings.Where(str => !string.IsNullOrEmpty(str)).Aggregate("", (current, str) => current + (str + strSeparator)); int trimEndStartIndex = strRetVal.Length - strSeparator.Length; if (trimEndStartIndex>0) strRetVal = strRetVal.Remove(trimEndStartIndex); return strRetVal; } 

我写了一些扩展方法,以有效的方式做到这一点:

  public static string JoinWithDelimiter(this IEnumerable<String> that, string delim) { var sb = new StringBuilder(); foreach (var s in that) { sb.AppendToList(s,delim); } return sb.ToString(); } 

这取决于

  public static string AppendToList(this String s, string item, string delim) { if (s.Length == 0) { return item; } return s+delim+item; } 

您可以在ListsIEnumerables上使用.ToArray() ,然后根据需要使用String.Join()