代码之家  ›  专栏  ›  技术社区  ›  Daniel Fortunov

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

  •  735
  • Daniel Fortunov  · 技术社区  · 15 年前

    从列表中创建以逗号分隔的字符串值列表的最干净的方法是什么 IList<string> IEnumerable<string>

    String.Join(...) 在一个 string[] 因此,在处理诸如

    21 回复  |  直到 15 年前
        1
  •  1625
  •   Community CDub    7 年前

    .NET 4+

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

    详情及;Net 4.0之前的解决方案

    IEnumerable<string> 可以转换为字符串数组 非常

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

    但后者有点言过其实:)

    这可能是最简单的方法,而且性能也很好——关于性能到底是什么样的还有其他问题,包括(但不限于) this one .

    string.Join

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

    简单得多:)

        2
  •  182
  •   Xavier Poinas    11 年前

    string.Join() 有一些 extra overloads ,这与 IEnumerable T :

    public static string Join(string separator, IEnumerable<string> values)
    public static string Join<T>(string separator, IEnumerable<T> values)
    
        3
  •  69
  •   Daniel Fortunov    15 年前

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

    string commaSeparatedList = input.Aggregate((a, x) => a + ", " + x)
    
        4
  •  33
  •   Dan VanWinkle tvanfosson    12 年前

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

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

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

    无需创建助手函数,它内置于.NET4.0及更高版本中。

        5
  •  16
  •   Roman Pokrovskij Archil Labadze    5 年前

    通过性能比较,获胜者是“循环它,某人附加它,然后后退”。 实际上,“可枚举和手动下一步移动”是同样好的(考虑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

        6
  •  12
  •   sam    8 年前

    var commaDelimited = string.Join(",", students.Where(i => i.Category == studentCategory)
                                     .Select(i => i.FirstName));
    
        7
  •  9
  •   Chris McKenzie    14 年前

    下面是另一种扩展方法:

        public static string Join(this IEnumerable<string> source, string separator)
        {
            return string.Join(separator, source);
        }
    
        8
  •  8
  •   David Clarke    10 年前

    这次讨论来得有点晚,但这是我对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();});
    

    又短又甜,使用StringBuilder构造新字符串,将StringBuilder长度缩短1以删除最后一个逗号并返回CSV字符串。

    Append() 添加字符串+逗号。根据詹姆斯的反馈,我用反射器看了一眼 StringBuilder.AppendFormat() . 原来 AppendFormat() Appends()

        9
  •  7
  •   Mike Kingscott    14 年前

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

    在将转换器(在本例中,d=>d.DivisionID.ToString(“b”))提供给列表后,从列表中提供CSV。

        10
  •  7
  •   Konrad Viltersten    12 年前

    以下是我的做法,使用我在其他语言中的做法:

    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();
    }
    
        11
  •  7
  •   serhio    11 年前

    具体需要时,我们应该围绕着',例如:

            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()));
    
        12
  •  4
  •   Keith    15 年前

    我们有一个效用函数,类似这样:

    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之前有collection参数,因为intellisense随后会选择集合类型。

    如果已经有字符串枚举,则只需执行ToArray:

    string csv = string.Join( ",", myStrings.ToArray() );
    
        13
  •  3
  •   Vikram    15 年前

    Dim strs As New List(Of String)
    Dim arr As Array
    arr = strs.ToArray
    
        14
  •  3
  •   Richard    15 年前

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

       var stringArray = stringList.ToArray();
    
        15
  •  3
  •   Brad    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();
            }
        }
    }
    

    编辑: Here

        16
  •  3
  •   SpaceKat    11 年前

    我只是在阅读本文之前解决了这个问题。我的解决方案如下所示:

       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)); 
    
        17
  •  3
  •   David Clarke    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()调用,我想将其重构为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-- 需要黑客。

    在我的框架库中,我对这个方法签名做了一些修改,包括 delimiter converter "," x.ToString() 分别作为默认值。

        18
  •  3
  •   Aran Mulholland JohnnyAce    9 年前

    希望这是最简单的方法

     string Commaseplist;
     string[] itemList = { "Test1", "Test2", "Test3" };
     Commaseplist = string.join(",",itemList);
     Console.WriteLine(Commaseplist); //Outputs Test1,Test2,Test3
    
        19
  •  3
  •   Håkon Seljåsen    9 年前

    我是在寻找一个好的C#方法来连接字符串时讨论这个问题的,就像使用MySql方法一样 CONCAT_WS() . 此方法不同于 string.Join()

    CONCAT_WS(“,”,待定。Lastname,待定。Firstname)

    Lastname 如果firstname为空,则

    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;
        }
    
        20
  •  3
  •   Saksham Chaudhary    5 年前

    如果要连接的字符串位于对象列表中,则也可以执行以下操作:

    var studentNames = string.Join(", ", students.Select(x => x.name));
    
        21
  •  2
  •   Paul Houle    15 年前

        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;
        }
    
        22
  •  2
  •   Michael Fredrickson    13 年前

    你可以用 .ToArray() Lists IEnumerables ,然后使用 String.Join()

        23
  •  0
  •   AlexMelw    4 年前

    从列表中创建逗号分隔列表的步骤 IList<string> IEnumerable<string> ,除了使用 string.Join() 你可以使用 StringBuilder.AppendJoin 方法:

    new StringBuilder().AppendJoin(", ", itemList).ToString();
    

    $"{new StringBuilder().AppendJoin(", ", itemList)}";