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

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

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

简单得多:)

仅供参考,.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)

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

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

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

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

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

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

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

这是另一种扩展方法:

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

到达讨论的时间有点晚,但这是我的贡献。我有一个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()的。

有点笨拙,但是可以工作:

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