【问题标题】:Join collection of objects into comma-separated string将对象集合加入逗号分隔的字符串中
【发布时间】:2008-12-01 10:45:26
【问题描述】:

在我们的代码中的许多地方,我们都有对象集合,我们需要从中创建一个逗号分隔的列表。集合的类型各不相同:它可能是我们需要某个列的 DataTable,也可能是 List 等。

现在我们遍历集合并使用字符串连接,例如:

string text = "";
string separator = "";
foreach (DataRow row in table.Rows)
{
    text += separator + row["title"];
    separator = ", ";
}

有没有更好的模式呢?理想情况下,我想要一种我们可以重用的方法,只需发送一个函数即可从每个对象中获取正确的字段/属性/列。

【问题讨论】:

    标签: c# .net .net-3.5


    【解决方案1】:
    string.Join(", ", Array.ConvertAll(somelist.ToArray(), i => i.ToString()))
    

    【讨论】:

    • 漂亮干净。如果 someList 被声明为 IList 怎么办?它缺少 ToArray() 方法。
    • @CristiDiaconescu: string.Join(", ", somelist.Select(t => t.ToString()).ToArray())
    • 我收到System.Array does not contain a definition for 'Convert'
    • @JoshStodola:说什么?你试图用 JVM 编译? ;p 从 1.0 开始就存在了。
    • @leppie 错了。它是not in 1.1,它是not in 2.0,它是not in 3.5。我想你的意思是ConvertAll
    【解决方案2】:
    static string ToCsv<T>(IEnumerable<T> things, Func<T, string> toStringMethod)
    {
        StringBuilder sb = new StringBuilder();
    
        foreach (T thing in things)
            sb.Append(toStringMethod(thing)).Append(',');
    
        return sb.ToString(0, sb.Length - 1); //remove trailing ,
    }
    

    这样使用:

    DataTable dt = ...; //datatable with some data
    Console.WriteLine(ToCsv(dt.Rows, row => row["ColName"]));
    

    或:

    List<Customer> customers = ...; //assume Customer has a Name property
    Console.WriteLine(ToCsv(customers, c => c.Name));
    

    我手头没有编译器,但理论上它应该可以工作。众所周知,在理论上,实践和理论是相同的。实际上,它们不是。

    【讨论】:

    • 这就是我要找的,谢谢!这里的理论与实践不同,您需要为该方法提供两个重载(一个用于泛型,一个用于非泛型),就像在 Hosam Aly 的回答中一样。不过,您的答案更容易阅读。
    • 这是最好的答案,特别是如果您坚持使用 BigBlondViking 的改进,使其成为一种扩展方法。更干净,适用于复杂的对象。
    【解决方案3】:

    我发现 string.Join 和 lambda Select&lt;Func&lt;&gt;&gt; 有助于编写最少的代码。

    List<string> fruits = new List<string>();
    fruits.Add("Mango");
    fruits.Add("Banana");
    fruits.Add("Papaya");
    
    string commaSepFruits = string.Join(",", fruits.Select(f => "'" + f + "'"));
    Console.WriteLine(commaSepFruits);
    
    List<int> ids = new List<int>();
    ids.Add(1001);
    ids.Add(1002);
    ids.Add(1003);
    
    string commaSepIds = string.Join(",", ids);
    Console.WriteLine(commaSepIds);
    
    List<Customer> customers = new List<Customer>();
    customers.Add(new Customer { Id = 10001, Name = "John" });
    customers.Add(new Customer { Id = 10002, Name = "Robert" });
    customers.Add(new Customer { Id = 10002, Name = "Ryan" });
    
    string commaSepCustIds = string.Join(", ", customers.Select(cust => cust.Id));
    string commaSepCustNames = string.Join(", ", customers.Select(cust => "'" + cust.Name + "'"));
    
    Console.WriteLine(commaSepCustIds);
    Console.WriteLine(commaSepCustNames);
    
    Console.ReadLine();
    

    【讨论】:

      【解决方案4】:
      // using System.Collections;
      // using System.Collections.Generic;
      // using System.Linq
      
      public delegate string Indexer<T>(T obj);
      
      public static string concatenate<T>(IEnumerable<T> collection, Indexer<T> indexer, char separator)
      {
          StringBuilder sb = new StringBuilder();
          foreach (T t in collection) sb.Append(indexer(t)).Append(separator);
          return sb.Remove(sb.Length - 1, 1).ToString();
      }
      
      // version for non-generic collections
      public static string concatenate<T>(IEnumerable collection, Indexer<T> indexer, char separator)
      {
          StringBuilder sb = new StringBuilder();
          foreach (object t in collection) sb.Append(indexer((T)t)).Append(separator);
          return sb.Remove(sb.Length - 1, 1).ToString();
      }
      
      // example 1: simple int list
      string getAllInts(IEnumerable<int> listOfInts)
      {
          return concatenate<int>(listOfInts, Convert.ToString, ',');
      }
      
      // example 2: DataTable.Rows
      string getTitle(DataRow row) { return row["title"].ToString(); }
      string getAllTitles(DataTable table)
      {
          return concatenate<DataRow>(table.Rows, getTitle, '\n');
      }
      
      // example 3: DataTable.Rows without Indexer function
      string getAllTitles(DataTable table)
      {
          return concatenate<DataRow>(table.Rows, r => r["title"].ToString(), '\n');
      }
      

      【讨论】:

      • 这正是我想要实现的,谢谢!虽然我发现 lambda 表达式更具可读性(就像在 Matt 的解决方案中一样)。
      • 我同意 lambda 表达式更具可读性,但到目前为止我只使用过 .NET 2.0。我希望尽快学会它们。
      • 您可能希望将分隔符更改为字符串而不是字符,但不要忘记将“sb.Remove”调用更改为“sb.Remove(sb.Length -分隔符.长度,分隔符.长度)“
      【解决方案5】:

      在 .NET 4 中,您只需执行 string.Join(", ", table.Rows.Select(r =&gt; r["title"]))

      【讨论】:

        【解决方案6】:

        您可以编写一个函数,将 IEnumerable 转换为逗号分隔的字符串:

        public string Concat(IEnumerable<string> stringList)
        {
            StringBuilder textBuilder = new StringBuilder();
            string separator = String.Empty;
            foreach(string item in stringList)
            {
                textBuilder.Append(separator);
                textBuilder.Append(item);
                separator = ", ";
            }
            return textBuilder.ToString();
        }
        

        然后您可以使用 LINQ 查询您的集合/数据集/等以提供 stringList。

        【讨论】:

        • 虽然 Join 可能是我通常会采用的方式,但我总是喜欢看到这种在第一次迭代中使用空分隔符并在后续迭代中使用所需分隔符的习惯用法。它看起来比总是添加分隔符然后必须将其剥离更干净。
        • 刚刚注意到我以错误的顺序添加了分隔符和项目...真傻!修复它:-)
        【解决方案7】:

        顺便说一句:我要做的第一个修改是使用StringBuilder Class 而不仅仅是一个字符串——它会为你节省资源。

        【讨论】:

          【解决方案8】:

          我喜欢这篇文章中的Matt Howells answer

          我不得不把它变成一个扩展:

          public static string ToCsv<T>(this IEnumerable<T> things, Func<T, string> toStringMethod)
          

          用法(我正在获取所有电子邮件并将它们转换为电子邮件的CSV 字符串):

          var list = Session.Find("from User u where u.IsActive = true").Cast<User>();
          
          return list.ToCsv(i => i.Email);
          

          【讨论】:

          • 这正是我所做的。您还应该使用 return sb.ToString().TrimEnd(','); 删除尾随逗号。函数更清晰,如果你传递的枚举中没有元素,他的函数会抛出一个不能小于零长度的错误,因为 0 - 1 = -1。
          【解决方案9】:

          对于集合,您也可以使用此方法,例如:

          string.Join(", ", contactsCollection.Select(i => i.FirstName));
          

          您可以选择要分离的任何属性。

          【讨论】:

            【解决方案10】:
            string strTest = "1,2,4,6";
            string[] Nums = strTest.Split(',');
            Console.Write(Nums.Aggregate<string>((first, second) => first + "," + second));
            //OUTPUT:
            //1,2,4,6
            

            【讨论】:

            • Aggregate 返回与输入值相同的数据类型,即据我所见,我无法将 List 聚合为字符串。
            • 也许 table.Rows.Select(r => r["title"].ToString()).Aggregate((a, b) => a + "," + b) 那么呢?
            【解决方案11】:

            这是我最喜欢的适合问题的答案, 并更正转换为 ConvertAll:

            string text = string.Join(", ", Array.ConvertAll(table.Rows.ToArray(), i => i["title"]));
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-08-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多