提问



IList<string>IEnumerable<string>创建以逗号分隔的字符串值列表的最简洁方法是什么?


String.Join(...)string[]上运行,因此当IList<string>IEnumerable<string>等类型不能轻易转换为字符串数组时,使用起来会很麻烦。

最佳参考


.NET 4 +


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


详情& Pre .Net 4.0解决方案


IEnumerable<string>可以使用LINQ(.NET 3.5)轻松转换为字符串数组 very :


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中有更多的重载,所以你实际上可以写:[68]


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


更简单:)

其它参考1


仅供参考,.NET !]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]**


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

其它参考2


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


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

其它参考3


我认为创建以逗号分隔的字符串值列表的最简洁方法是:


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


这是一个完整的例子:


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

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


没有必要创建一个辅助函数,这是内置于.NET 4.0及更高版本。

其它参考4


这是另一种扩展方法:


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

其它参考5


由于我在搜索连接对象列表的特定属性(而不是它的ToString())时到达此处,这里是对已接受答案的补充:


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

其它参考6


到达这个讨论稍晚,但这是我的贡献fwiw。我有一个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();});


Short和sweet,使用StringBuilder构造新字符串,将StringBuilder长度缩小一个以删除最后一个逗号并返回CSV字符串。


我已经更新了这个以使用多个Append()来添加字符串+逗号。来自James的反馈,我使用Reflector来查看StringBuilder.AppendFormat()。结果AppendFormat()使用StringBuilder来构造格式字符串,这使得它在这种情况下的效率低于仅使用多个Appends() S。

其它参考7


有点蠢,但它的作用:


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


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


Hacky但是有效 - 可能会被制作成扩展方法吗?

其它参考8


这就是我按照我在其他语言中使用它的方式做到的方式:


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();
}

其它参考9


按性能比较,获胜者是循环,加入,然后退步。
实际上可枚举和手动移动下一步是一样的好(考虑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 [70]

其它参考10


特别需要我们应该围绕,由ex:


        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()));

其它参考11


我们有一个实用功能,如下所示:


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之前有集合param,因为intellisense然后选择集合类型。


如果你已经有一个字符串的枚举,你需要做的就是ToArray:


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

其它参考12


我刚刚在本文发生之前解决了这个问题。我的解决方案如下:


   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)); 

其它参考13


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


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

其它参考14


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


   var stringArray = stringList.ToArray();

其它参考15


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


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();
        }
    }
}


 这是另一个例子[71]

其它参考16


我的答案就像上面的聚合解决方案,但由于没有明确的委托调用,所以应该减少调用堆栈的重量:


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()来确定是否写一个逗号。如果我遇到它,我会捣乱并发布解决方案。





这是我最初想要的:


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()作为默认值。

其它参考17


希望这是最简单的方法


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

其它参考18


我在寻找一个好的C#方法来加入这个讨论,就像使用MySql方法CONCAT_WS()一样加入字符串。此方法与string.Join()方法的不同之处在于,如果字符串为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;
    }

其它参考19


我写了一些扩展方法,以一种有效的方式完成它:


    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;
    }

其它参考20


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