Answers:
.NET 4+
IList<string> strings = new List<string>{"1","2","testing"};
string joined = string.Join(",", strings);
.Net 4.0之前的细节和解决方案
IEnumerable<string>
可以被转换成一个字符串数组非常与LINQ(.NET 3.5)容易:
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());
后者虽然有点a :)
这很可能是最简单的方法,而且性能也很高-关于性能到底是什么样,还有其他问题,包括(但不限于)这一问题。
从.NET 4.0开始,中提供了更多的重载string.Join
,因此您实际上可以编写:
string joined = string.Join(",", strings);
简单得多:)
List<T>
。为什么要重新发明轮子?
ToList
。很好用string myStr = string.Join(",", foo.Select(a => a.someInt.ToString()))
。
仅供参考,.NET 4.0版本string.Join()
具有一些额外的重载,它们IEnumerable
不仅可以处理数组,还可以处理数组,包括可以处理任何类型的数组T
:
public static string Join(string separator, IEnumerable<string> values)
public static string Join<T>(string separator, IEnumerable<T> values)
str = emps.Select(e => e.SSN).Join(",")
我可以看到的最简单的方法是使用LINQ Aggregate
方法:
string commaSeparatedList = input.Aggregate((a, x) => a + ", " + x)
Func<StringBuilder,string,StringBuider>
。然后只需调用ToString()
返回的StringBuilder。当然,它不是那么漂亮:)
input.Count
应大于1
我认为创建以逗号分隔的字符串值列表的最简单方法是:
string.Join<string>(",", stringEnumerable);
这是一个完整的示例:
IEnumerable<string> stringEnumerable= new List<string>();
stringList.Add("Comma");
stringList.Add("Separated");
string.Join<string>(",", stringEnumerable);
.NET 4.0及更高版本内置了此功能。
通过性能比较获胜者是“抱住它,附加它,然后退一步”。实际上,“下一个可枚举和手动移动”是一样的好事(考虑到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();
}
}
到达讨论的时间有点晚,但这是我的贡献。我有一个IList<Guid> OrderIds
要转换为CSV字符串的方法,但是以下方法是通用的,并且未修改其他类型的方法:
string csv = OrderIds.Aggregate(new StringBuilder(),
(sb, v) => sb.Append(v).Append(","),
sb => {if (0 < sb.Length) sb.Length--; return sb.ToString();});
简短而有趣,使用StringBuilder构造新的字符串,将StringBuilder的长度缩小1以删除最后一个逗号并返回CSV字符串。
我已经对此进行了更新,以使用多个Append()
来添加字符串+逗号。从James的反馈中,我使用Reflector进行了查看StringBuilder.AppendFormat()
。事实证明,AppendFormat()
使用StringBuilder来构造格式字符串,这使其在这种情况下的效率比仅使用多个都低Appends()
。
我们有一个实用程序函数,如下所示:
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然后选择了集合类型。
如果您已经有了字符串枚举,则只需要做ToArray:
string csv = string.Join( ",", myStrings.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();
}
}
}
编辑: 这是另一个例子
我只是在解决本文之前就解决了这个问题。我的解决方案如下所示:
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);
}
我也可以像这样轻松表达,也可以提高效率:
string.Join(“,”, myThings.Select(t => string.format(“Thing {0} is a {1}”, t.id, t.name));
我的答案类似于上面的聚合解决方案,但由于没有显式的委托调用,因此应减少调用栈的负担:
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上的正则循环,并使用MoveNext()确定是否编写逗号。如果遇到问题,我会摆弄并发布该解决方案。
这是我最初想要的:
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--
帮闲需要。
在我的框架库中,我对该方法签名进行了一些更改,分别包含delimiter
和的每个组合以及converter
使用","
和x.ToString()
作为默认值的参数。
我在寻找一个好的C#方法来连接字符串时遇到了这个讨论,就像使用MySql方法一样CONCAT_WS()
。此方法与方法的不同之处在于,string.Join()
如果字符串为NULL或为空,则不添加分隔符。
CONCAT_WS(',',tbl.Lastname,tbl.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;
}
public static TSource[] ToArray<TSource>(this IEnumerable<TSource> source)