关于c#:从IList创建逗号分隔列表

Creating a comma separated list from IList<string> or IEnumerable<string>

IListIEnumerable创建字符串值的逗号分隔列表最干净的方法是什么?

String.Join(...)string[]上运行,因此当类型(如IListIEnumerable不容易转换为字符串数组时,使用该类型可能比较麻烦。


4 +。

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

详细&;4.0前网解决方案。

IEnumerable可以转换成一个字符串数组很容易和LINQ(。NET 3.5):

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

它容易写足以当量法:如果你需要帮手

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

然后调用它像这样:

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

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

1
2
3
4
// 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());

后者是一个mouthful虽然:)

这是可能的最简单的方式做它,和安静性能。也有其他问题-关于到底是什么样的性能,包括(但不限于)这一个。

作为.NET 4.0中,有更多的overloads string.Join可用,所以你可以真的只是写:

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

很简单的:)


FYI,.NET 4.0版,有一些额外的String.Join()overloads,这与IEnumerable而只是阵列,包括一个可以处理任何类型T

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


在最简单的方式做,这是我能看到的Aggregate法:使用LINQ

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


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

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

下面是一个完整的例子:

1
2
3
4
5
IEnumerable<string> stringEnumerable= new List<string>();
stringList.Add("Comma");
stringList.Add("Separated");

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

不需要创建助手函数,它内置于.NET 4.0及更高版本中。


因为我在搜索对象列表的特定属性(而不是它的toString())时到达这里,这里是对接受答案的一个补充:

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

通过性能比较,获胜者是"循环、附加、后退"。实际上,"Enumerable"和"ManualMoveNext"是相同的优点(考虑stddev)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 |

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
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


这是一个扩展的方法:

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

到达一个小晚,但这本是我的贡献,fwiw。我有一个CSV IList OrderIds的转换字符串,但以下是通用和其他类型的作品有:unmodified

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

短和甜蜜,建构新的使用StringBuilder的字符串长度由一shrinks StringBuilder,解除负荷和CSV逗号的字符串返回。

我已经更新这个使用多Append()+添加逗号的字符串。从詹姆斯的反馈使用一个反射器,一看StringBuilder.AppendFormat()。原来to construct a AppendFormat()使用StringBuilder的字符串格式,使它不在本发明高效多Appends()不只是使用它。


这是我的方式做它,做它的方式我已经使用的其他语言:

1
2
3
4
5
6
7
8
9
10
11
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();
}


一位丑陋的东西,但它的工作原理:

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

给你一个CSV名单后你给它的转换器(在本案例d.divisionid.tostring D = >("B")。

哈克,但工程的制造方法可以扩展到任何?


当我们应该被包围时的特殊需要,例如:

1
2
3
4
5
6
7
        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()));

我们有一个效用函数是这样的:

1
2
3
4
5
6
public static string Join<T>( string delimiter,
    IEnumerable<T> collection, Func<T, string> convert )
{
    return string.Join( delimiter,
        collection.Select( convert ).ToArray() );
}

可以用于很多容易:加入收藏

1
2
3
int[] ids = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233};

string csv = StringUtility.Join(",", ids, i => i.ToString() );

注意,我们在收集参数λ因为IntelliSense就在选秀上收集的类型。

如果你已经有一个枚举的字符串,你需要做的所有大学的拷贝。

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


希望这是最简单的方法

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

我刚刚解决了这个问题,然后才在本文中讨论。我的解决方案如下:

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

叫作:

1
2
3
4
5
6
7
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);
}

我也可以这样轻易地表达出来,而且效率也会更高:

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


所以,你可以使用什么样的信息后,你有一个转换的一个数组的使用方法:由他人所有的学院

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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();
        }
    }
}

编辑:这里是另一个例子


他们可以很容易转换到阵列使用.NET 3.5中的LINQ的扩展。

1
   var stringArray = stringList.ToArray();

我在寻找一个好的C方法来连接字符串的时候讨论了这个问题,就像使用mysql方法CONCAT_WS()一样。此方法与string.Join()方法的不同之处在于,如果字符串为空或为空,则不添加分隔符符号。

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

如果firstname为空,则只返回Lastname,而

string.Join(",", strLastname, strFirstname)

在同一情况下将返回strLastname +","

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    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;
    }

你可以使用一个数组转换的ilist拷贝,然后运行一个string.join指挥数组。

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

我的答案是以上的骨料应样解决方案但不调用栈重因为没有明确的代表电话:

1
2
3
4
5
6
7
8
9
10
11
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)呼叫(我想是做直动过在while循环和使用IEnumerable MoveNext()确定是否或不写逗号。我的小提琴后,绕过解决方案如果我走在它。

这里是我想要的。

1
2
3
4
5
6
7
8
9
10
11
12
13
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();
}

临时数组或列表存储所需的NO和NO StringBuilderRemove()Length--黑客或要求。

在我的图书馆的一个框架的制造变化,在这一方法的签名,每个组合包括一个converterdelimiter和参数使用的","x.ToString()作为缺省值,分别为。


我写了一个扩展的方法做它在一方式,这是有效的:

1
2
3
4
5
6
7
8
    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();
    }

这取决于

1
2
3
4
5
6
7
    public static string AppendToList(this String s, string item, string delim) {
        if (s.Length == 0) {
            return item;
        }

        return s+delim+item;
    }


你可以使用.ToArray()ListsIEnumerablesString.Join(),然后使用你想要的。