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

Dan*_*nov 806 c# string

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

String.Join(...)上的操作string[],从而可能是麻烦的与当类型,如工作IList<string>IEnumerable<string>不能容易地被转换成一个字符串数组.

Jon*_*eet 1378

.NET 4+

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

详细信息和Pre .Net 4.0解决方案

IEnumerable<string>使用LINQ(.NET 3.5)可以容易地将其转换为字符串数组:

IEnumerable<string> strings = ...;
string[] array = strings.ToArray();
Run Code Online (Sandbox Code Playgroud)

如果需要,可以很容易地编写等效的辅助方法:

public static T[] ToArray(IEnumerable<T> source)
{
    return new List<T>(source).ToArray();
}
Run Code Online (Sandbox Code Playgroud)

然后像这样称呼它:

IEnumerable<string> strings = ...;
string[] array = Helpers.ToArray(strings);
Run Code Online (Sandbox Code Playgroud)

然后你可以打电话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());
Run Code Online (Sandbox Code Playgroud)

后者虽然有点满口:)

这可能是最简单的方法,并且性能也非常高 - 还有其他问题,关于性能是什么样的,包括(但不限于)这个.

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

string joined = string.Join(",", strings);
Run Code Online (Sandbox Code Playgroud)

更简单:)

  • 而已.每个答案都会导致Jon Skeet.我要去var PurchaseBooks = AmazonContainer.Where(p => p.Author =="Jon Skeet").选择(); (38认同)
  • 不,重点是结果需要是一个连接的字符串.无需创建新列表或新阵列即可实现此目标.这种.NET心态让我很伤心. (9认同)
  • 辅助方法只创建*one*list和*one*数组.关键是结果需要是一个数组,而不是一个列表......你需要在开始之前知道一个数组的大小.最佳实践表明,除非必须,否则不应在LINQ中多次枚举源代码 - 它可能会做各种令人讨厌的事情.所以,你只需要阅读缓冲区并调整大小 - 这正是`List <T>`的作用.为什么重新发明轮子? (4认同)
  • @ codeMonkey0110:那里有一个查询表达式或调用`ToList`是没有意义的.可以使用`string myStr = string.Join(",",foo.Select(a => a.someInt.ToString()))`. (3认同)

Xav*_*nas 177

仅供参考,.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)
Run Code Online (Sandbox Code Playgroud)

  • @PhilippeLavoie是的 (3认同)
  • 这会调用T.ToString()方法吗? (2认同)
  • 无论如何要在对象的属性上执行此操作?(例如:IEnumerable <Employee>和Employee对象上有一个字符串.SSN属性,并获得一个以逗号分隔的SSN列表.) (2认同)

Dan*_*nov 64

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

string commaSeparatedList = input.Aggregate((a, x) => a + ", " + x)
Run Code Online (Sandbox Code Playgroud)

  • 不过,这是最漂亮的. (34认同)
  • 这不仅比ToArray + Join更复杂(IMO),它也有些低效 - 输入序列很大,开始表现非常糟糕. (18认同)
  • 请注意`input.Count`应该大于1. (7认同)
  • 这是做恕我直言的问题的最明确的方式. (3认同)
  • 您可以为Aggregate提供StringBuilder种子,然后您的Aggregate Func变为`Func <StringBuilder,string,StringBuider>`.然后在返回的StringBuilder上调用`ToString()`.它当然不是那么漂亮:) (2认同)

Dan*_*kle 31

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

string.Join<string>(",", stringEnumerable);
Run Code Online (Sandbox Code Playgroud)

这是一个完整的例子:

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

string.Join<string>(",", stringEnumerable);
Run Code Online (Sandbox Code Playgroud)

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

  • 请注意,这适用于从.NET 4开始(正如Xavier在他的回答中指出的那样). (4认同)

Sak*_*ary 23

如果您要加入的字符串位于对象列表中,那么您也可以执行以下操作:

var studentNames = string.Join(", ", students.Select(x => x.name));
Run Code Online (Sandbox Code Playgroud)

  • @Lucifer你可以试试这个:var StudentNames = string.Join(", ", Students.Where(x =&gt; !string.IsNullOrEmpty(x)).Select(x =&gt; x.name)); (2认同)

Rom*_*kij 11

按性能比较,获胜者是"循环,加入,然后退步".实际上"可枚举和手动移动下一步"是一样的好(考虑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 |
Run Code Online (Sandbox Code Playgroud)

码:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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


sam*_*sam 10

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

var commaDelimited = string.Join(",", students.Where(i => i.Category == studentCategory)
                                 .Select(i => i.FirstName));
Run Code Online (Sandbox Code Playgroud)


Chr*_*zie 9

这是另一种扩展方法:

    public static string Join(this IEnumerable<string> source, string separator)
    {
        return string.Join(separator, source);
    }
Run Code Online (Sandbox Code Playgroud)


Dav*_*rke 8

到达这个讨论稍晚,但这是我的贡献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();});
Run Code Online (Sandbox Code Playgroud)

简短而甜蜜,使用StringBuilder构造新字符串,将StringBuilder长度缩小一个以删除最后一个逗号并返回CSV字符串.

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

  • 这将使零项IEnumerable源失败.sb.Length--需要边界检查. (2认同)

Mik*_*ott 7

有点蠢,但它的工作原理:

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

在给出转换器后给出列表中的CSV(在这种情况下d => d.DivisionID.ToString("b")).

Hacky但是有效 - 可能会成为一种扩展方法吗?


小智 7

这是我使用其他语言完成它的方式:

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();
}
Run Code Online (Sandbox Code Playgroud)


ser*_*hio 7

特殊需要我们应该围绕',由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()));
Run Code Online (Sandbox Code Playgroud)