2008-12-01 53 views
25

Ở nhiều nơi trong mã của chúng tôi, chúng tôi có các bộ sưu tập đối tượng, từ đó chúng tôi cần tạo danh sách được phân cách bằng dấu phẩy. Các loại bộ sưu tập khác nhau: nó có thể là một DataTable từ đó chúng ta cần một cột nào đó, hoặc một danh sách khách hàng < > vvTham gia tập hợp các đối tượng thành chuỗi được phân tách bằng dấu phẩy

Bây giờ chúng ta lặp qua nối việc thu thập và sử dụng chuỗi, ví dụ:

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

Có mô hình nào tốt hơn cho điều này không? Lý tưởng nhất là tôi muốn một cách tiếp cận chúng ta có thể tái sử dụng bằng cách chỉ cần gửi trong một hàm để có được trường/thuộc tính/cột đúng từ mỗi đối tượng.

Trả lời

10
// 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'); 
} 
+1

Điều này thực hiện chính xác những gì tôi muốn đạt được, cảm ơn bạn! Mặc dù tôi thấy các biểu thức lambda dễ đọc hơn (như trong giải pháp của Matt). –

+1

Tôi đồng ý rằng các biểu thức lambda dễ đọc hơn nhiều, nhưng tôi chỉ sử dụng .NET 2.0 cho đến nay. Tôi hy vọng sẽ sớm tìm hiểu chúng. –

+1

Bạn có thể muốn thay đổi dấu tách thành một chuỗi thay vì char, nhưng sau đó đừng quên thay đổi "sb.Remove" gọi thành "sb.Remove (sb.Length - separator.Length, separator.Length) " –

2

Là một sang một bên: Sửa đổi đầu tiên tôi sẽ thực hiện là sử dụng StringBuilder Class thay vì chỉ một chuỗi - nó sẽ lưu tài nguyên cho bạn.

11
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 , 
} 

Sử dụng như thế này:

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

hay:

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

Tôi không có một trình biên dịch để bàn nhưng về mặt lý thuyết nó phải làm việc. Và như mọi người đều biết, trong lý thuyết, thực hành và lý thuyết là như nhau. Trong thực tế, họ không.

+0

Đây là những gì tôi đang tìm kiếm, cảm ơn bạn! Lý thuyết không giống như thực hành ở đây, bạn cần hai quá tải cho phương pháp (một cho generics và một cho không generics), giống như trong câu trả lời của Hosam Aly. Câu trả lời của bạn dễ đọc hơn rất nhiều. –

+0

Đây là câu trả lời hay nhất, đặc biệt là nếu bạn làm theo với cải tiến của BigBlondViking trong việc biến nó thành một phương pháp mở rộng. Sạch hơn nhiều và hoạt động cho các đối tượng phức tạp. – smdrager

6

Bạn có thể viết một hàm biến đổi một IEnumerable thành một dấu phẩy tách chuỗi

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

Sau đó bạn có thể sử dụng LINQ để truy vấn sưu tập của bạn/dữ liệu/etc để cung cấp các stringList.

+0

Trong khi Tham gia có lẽ là cách mà tôi thường đi, tôi luôn luôn muốn thấy thành ngữ này bằng cách sử dụng dấu tách trống trong lần lặp đầu tiên và dấu tách mong muốn trong phần tiếp theo. Nó trông sạch hơn bao giờ cũng thêm dấu phân cách và sau đó phải tách nó ra sau đó. – wageoghe

+0

Chỉ cần nhận thấy tôi đã thêm dấu phân cách và các mục theo thứ tự sai ... ngớ ngẩn tôi! Đã sửa lỗi :-) – Mendelt

88
string.Join(", ", Array.ConvertAll(somelist.ToArray(), i => i.ToString())) 
+1

đẹp và sạch sẽ. Điều gì sẽ xảy ra nếu someList được khai báo là IList? Nó thiếu phương thức ToArray(). –

+4

@CristiDiaconescu: string.Join (",", somelist.Select (t => t.ToString()) ToArray()) – cederlof

+0

Tôi nhận được 'System.Array không chứa định nghĩa cho 'Convert'' –

1
string strTest = "1,2,4,6"; 
string[] Nums = strTest.Split(','); 
Console.Write(Nums.Aggregate<string>((first, second) => first + "," + second)); 
//OUTPUT: 
//1,2,4,6 
+0

Tổng hợp trả về cùng một kiểu dữ liệu như các giá trị đầu vào, tức là theo như tôi thấy, tôi không thể tổng hợp một Danh sách thành một chuỗi. –

+0

Có thể table.Rows.Select (r => r ["title"]. ToString()). Tổng hợp ((a, b) => a + "," + b) sau đó? –

2

Tôi yêu Matt Howells answer trong bài viết này:

Tôi phải làm cho nó thành một phần mở rộng:

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

Cách sử dụng: [Tôi nhận được tất cả các email và biến chúng thành chuỗi csv cho email]:

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

return list.ToCsv(i => i.Email); 
+0

Đây chính xác là những gì tôi đã làm. Bạn cũng nên sử dụng return 'sb.ToString(). TrimEnd (',');' để loại bỏ dấu phẩy sau. Nó rõ ràng hơn trong hàm và nếu không có phần tử nào trong số đếm bạn vượt qua nó, hàm của nó sẽ ném một lỗi không thể-ít hơn 0 độ dài từ 0 - 1 = -1. – smdrager

5

Trong .NET 4 bạn chỉ có thể làm string.Join(", ", table.Rows.Select(r => r["title"]))

10

tôi thấy string.Join và Lambda Chọn> giúp viết mã tối thiểu.

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

Dưới đây là câu trả lời yêu thích của tôi phù hợp với câu hỏi, và chỉnh Convert to ConvertAll:

string text = string.Join(", ", Array.ConvertAll(table.Rows.ToArray(), i => i["title"])); 
Các vấn đề liên quan