2009-06-14 17 views
6

lớp String chứa phương pháp rất hữu ích - String.Join(string, string[]).Tương tự của String.Join (chuỗi, chuỗi []) cho IEnumerable <T>

Nó tạo ra một chuỗi từ một mảng, tách từng phần tử của mảng bằng ký hiệu được cho. Nhưng nói chung - nó không thêm dấu tách sau phần tử cuối cùng! Tôi sử dụng nó cho mã hóa ASP.NET để tách với "<br />" hoặc Environment.NewLine.

Vì vậy, tôi muốn thêm hàng trống sau mỗi hàng trong asp:Table. Phương pháp nào của tôi có thể sử dụng cho cùng một chức năng?

+0

Chỉ cần một TableRow mới cho các giá trị chèn? – spender

+0

'IEnumerable 'hoạt động như thế nào với phương thức kết nối có chuỗi, nói cách khác, bạn thực sự đang gọi phương thức hiện tại như thế nào? Tôi không hiểu chính xác những gì bạn đang tìm kiếm ở đây. –

+1

Tôi hiện không gọi 'String.Join'. Chỉ cần tìm kiếm cùng một chức năng - chèn dấu phân tách giữa các phần tử của mảng – abatishchev

Trả lời

8

tôi đã viết một phương pháp khuyến nông:

public static IEnumerable<T> 
     Join<T>(this IEnumerable<T> src, Func<T> separatorFactory) 
    { 
     var srcArr = src.ToArray(); 
     for (int i = 0; i < srcArr.Length; i++) 
     { 
      yield return srcArr[i]; 
      if(i<srcArr.Length-1) 
      { 
       yield return separatorFactory(); 
      } 
     } 
    } 

Bạn có thể sử dụng nó như sau:

tableRowList.Join(()=>new TableRow()) 
+2

Trừ khi tôi hiểu sai câu hỏi, mã trên không có ý nghĩa gì cả. Nó trả về một dấu phân cách * tại chỗ * của mục cuối cùng ?? Gì? –

+0

Có vẻ như mr. @abatischev thay đổi mã của tôi. Hừm. Kiểm tra rev 1. Grrr. – spender

+0

Tôi vừa thiết kế lại indents một chút, theo như tôi có thể nhớ =) xin lỗi nếu bị quấy rầy, quay trở lại mà không nghi ngờ gì nếu nghĩ rằng nó cần thiết – abatishchev

0

Không có phương thức tích hợp sẵn để làm điều đó, bạn nên tự cuộn.

+1

"Phương thức nào của IEnumerable ...?" Đây là câu trả lời đúng, mặc dù không hữu ích. Chắc chắn không có giá trị một downvote. – spender

1

Nếu tôi không thể tìm thấy một phương pháp phù hợp với nhu cầu của mình, tôi sẽ tự tạo. Và các phương pháp mở rộng rất đẹp theo cách đó vì chúng cho phép bạn mở rộng những thứ như thế. Không biết nhiều về asp: bảng, nhưng đây là một phương pháp gia hạn ít nhất mà bạn có thể tinh chỉnh để bất cứ điều gì: p

public static class TableRowExtensions 
{ 
    public string JoinRows(this IEnumerable<TableRow> rows, string separator) 
    { 
     // do what you gotta do 
    } 
} 
0

Nếu bạn định làm điều này thường xuyên, thì bạn nên xây dựng phương pháp mở rộng của riêng mình. Việc triển khai bên dưới cho phép bạn thực hiện tương đương với string.Join(", ", arrayOfStrings) trong đó arrayOfStrings có thể là IEnumerable<T> và trình tách có thể là đối tượng bất kỳ. Nó cho phép bạn làm điều gì đó như thế này:

var names = new [] { "Fred", "Barney", "Wilma", "Betty" }; 
var list = names 
    .Where(n => n.Contains("e")) 
    .Join(", "); 

Hai điều tôi thích về vấn đề này là:

  1. Nó rất có thể đọc được trong một bối cảnh LINQ.
  2. Nó khá hiệu quả vì nó sử dụng StringBuilder và tránh đánh giá việc liệt kê hai lần.
public static string Join<TItem,TSep>(
    this IEnumerable<TItem> enuml, 
    TSep     separator) 
{ 
    if (null == enuml) return string.Empty; 

    var sb = new StringBuilder(); 

    using (var enumr = enuml.GetEnumerator()) 
    { 
     if (null != enumr && enumr.MoveNext()) 
     { 
      sb.Append(enumr.Current); 
      while (enumr.MoveNext()) 
      { 
       sb.Append(separator).Append(enumr.Current); 
      } 
     } 
    } 

    return sb.ToString(); 
} 
+0

Nhưng nó đánh giá bộ sưu tập hai lần. Nếu đó là một truy vấn cơ sở dữ liệu thì nó không hiệu quả chút nào. Ngoài ra, nó sẽ tự nhiên hơn để mất các loại chung ở đây và làm cho nó hoạt động với các chuỗi chỉ. –

+0

@Lasse Vâng, đó là một điểm công bằng. Tôi đã giả định trong bộ nhớ chỉ. Bây giờ refactored để đếm được đánh giá chỉ một lần. –

+0

Tại sao bạn không sử dụng câu lệnh 'foreach'? Ngay bây giờ bạn có một sự rò rỉ có thể resouce. Bạn ít nhất phải sử dụng câu lệnh 'using' với' .GetEnumerator() '. –

5

Trong .NET 3.5 bạn có thể sử dụng phương pháp mở rộng này:

public static string Join<TItem>(this IEnumerable<TItem> enumerable, string separator) 
{ 
    return string.Join(separator, enumerable.Select(x => x.ToString()).ToArray()); 
} 

hoặc trong .NET 4

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

NHƯNG câu hỏi muốn có một tách sau mỗi phần tử trong đó có cuối cùng mà phiên bản này (phiên bản 3.5) sẽ hoạt động: -

public static string AddDelimiterAfter<TItem>(this IEnumerable<TItem> enumerable, string delimiter) 
{ 
    return string.Join("", enumerable.Select(x => x.ToString() + separator).ToArray()); 
} 

Bạn cũng có thể sử dụng .Đăng ký để thực hiện việc này mà không có phương pháp mở rộng.

8

Các LINQ tương đương với String.JoinAggregate

Ví dụ:

IEnumerable<string> strings; 
string joinedString = strings.Aggregate((total,next) => total + ", " + next); 

Nếu đưa ra một trình duyệt IE của TableRows, mã sẽ tương tự.

+3

Cảnh báo: điều này có thể tương đương với hàm 'String.Join', nhưng việc thực hiện khác nhau. 'String.Join' là đủ thông minh để sử dụng một' StringBuilder' để tránh phân bổ một bó toàn bộ các trường hợp 'String' tạm thời, trong khi mã trên không. –

+0

@KentBoogaart Tuy nhiên, điều này không quan trọng lắm, vì câu hỏi ban đầu là về cách tái tạo hành vi chung, 'string.Join' chỉ là một ví dụ về một hàm có hành vi 'giao nhau' đó. – Pharap

1

Điều bạn đang tìm kiếm là một hàm Intersperse. Để triển khai LINQ của một hàm như vậy, hãy xem this question.


Ngẫu nhiên, khác tương tự có thể xảy ra String.JoinIntercalate chức năng, mà thực sự là những gì tôi đang tìm kiếm:

public static IEnumerable<T> Intercalate<T>(this IEnumerable<IEnumerable<T>> source, 
              IEnumerable<T> separator) { 
    if (source == null) throw new ArgumentNullException("source"); 
    if (separator == null) throw new ArgumentNullException("separator"); 
    return source.Intersperse(separator) 
     .Aggregate(Enumerable.Empty<T>(), Enumerable.Concat); 
} 
Các vấn đề liên quan