2012-02-17 34 views
16

Có ai biết nếu có lý do cụ thể hoặc quyết định thiết kế không bao gồm điều tra ngược lại trong C# không? Nó sẽ rất tuyệt nếu có tương đương với C++ reverse_iterator giống như Enumerator tương đương với C++ iterator. Các bộ sưu tập có thể được đảo ngược-lặp sẽ chỉ thực hiện một cái gì đó giống như IReverseEnumerable và người ta có thể làm điều gì đó như:Tại sao không có ReverseEnumerator trong C#?

List<int>.ReverseEnumerator ritr = collection.GetReverseEnumerator(); 
while(rtir.MoveNext()) 
{ 
// do stuff 
} 

Bằng cách này, bạn sẽ có thể lặp Lists và LinkedLists trong cùng một cách hơn là sử dụng indexer cho một và các liên kết trước đó cho các kết nối khác do đó đạt được sự trừu tượng tốt hơn

+1

Câu hỏi thú vị, 'MoveNext()' sẽ kinda dường như một nghịch lý đối với một Enumerator ngược mặc dù tôi đoán cho tương thích với 'foreach' 'cái GetReverseEnumerator()' phương pháp sẽ thực sự vẫn phải trả về một 'IEnumerator' và do đó sẽ yêu cầu phương thức đó ngay cả khi' MovePrevious() 'có vẻ phù hợp hơn với tâm trí của tôi – RobV

+2

Có phương pháp mở rộng Reverse linq đạt được một cái gì đó tương tự ... – RQDQ

+3

Trên các kiểu thực hiện' IList ' một 'Reverse' hiệu quả từ linq. Thật không may, không phải mọi kiểu có thể thực thi 'Reverse' một cách hiệu quả, cũng có thể thực thi' IList '. Ví dụ: danh sách được liên kết kép. Vì vậy, tôi đồng ý, rằng những bộ sưu tập có xây dựng trong phương pháp 'Reverse()', sẽ được tốt đẹp. – CodesInChaos

Trả lời

21

Hoàn toàn có thể thực hiện điều này. Cá nhân tôi gần như không bao giờ đảo ngược. Nếu tôi cần làm điều này, tôi gọi .Reverse() trước tiên. Có lẽ đây là những gì các nhà thiết kế .NET BCL cũng nghĩ như vậy.

Tất cả các tính năng chưa được thực hiện theo mặc định. Chúng cần được thiết kế, triển khai, kiểm tra, ghi lại và hỗ trợ. - Raymond Chen

Và đây là lý do tại sao bạn không triển khai các tính năng cung cấp ít tiện ích. Bạn bắt đầu với các tính năng quan trọng nhất (như lặp lại từ trước ra sau). Và bạn dừng một nơi nào đó mà ngân sách của bạn cạn kiệt hoặc nơi bạn nghĩ là không có ý nghĩa để tiếp tục.

Có nhiều thứ không nằm trong thư viện lớp cơ sở .NET. Cho đến khi .NET 4 thậm chí không phải là File.EnumerateLines. Và tôi sẽ mạo hiểm để nói rằng một chức năng như vậy là quan trọng hơn lặp lại ngược cho hầu hết mọi người.

Có thể là trường hợp bạn đang làm việc trong miền doanh nghiệp, nơi lặp lại ngược lại là phổ biến. Kinh nghiệm của tôi là ngược lại. Là một nhà thiết kế khung, bạn chỉ có thể đoán ai sẽ sử dụng khung của bạn và những tính năng mà những người này sẽ yêu cầu. Thật khó để vẽ đường.

+2

Nó không được gọi là 'File.ReadLines'? – nawfal

11

Nó không khả dụng vì IEnumerable là trình chuyển tiếp chỉ chuyển tiếp. Nó chỉ có một phương thức MoveNext(). Điều đó làm cho giao diện rất phổ biến và cốt lõi của LINQ. Có rất nhiều bộ sưu tập thế giới thực không thể lặp lại vì yêu cầu phải có bộ nhớ. Hầu hết các luồng đều giống như vậy.

LINQ cung cấp giải pháp với phương thức mở rộng Reverse(). Nó hoạt động bằng cách lưu trữ các phần tử đầu tiên, sau đó lặp lại chúng. Tuy nhiên điều đó có thể rất lãng phí, nó yêu cầu lưu trữ O (n). Nó thiếu một tối ưu hóa có thể cho các bộ sưu tập đã được lập chỉ mục. Mà bạn có thể khắc phục: sử dụng

static class Extensions { 
    public static IEnumerable<T> ReverseEx<T>(this IEnumerable<T> coll) { 
     var quick = coll as IList<T>; 
     if (quick == null) { 
      foreach (T item in coll.Reverse()) yield return item; 
     } 
     else { 
      for (int ix = quick.Count - 1; ix >= 0; --ix) { 
       yield return quick[ix]; 
      } 
     } 
    } 
} 

mẫu:

 var list = new List<int> { 0, 1, 2, 3 }; 
     foreach (var item in list.ReverseEx()) { 
      Console.WriteLine(item); 
     } 

Bạn sẽ muốn thực hiện một chuyên môn hóa cho LinkedList vì nó không thực hiện IList <> nhưng vẫn cho phép nhanh chóng lùi lặp thông qua cuối và LinkedListNode.Previous properties. Mặc dù tốt hơn hết là không sử dụng lớp đó, nhưng nó có bộ nhớ cache cục bộ CPU tệ hại. Luôn ưu tiên Danh sách <> khi bạn không cần chèn giá rẻ.Nó có thể trông như thế này:

public static IEnumerable<T> ReverseEx<T>(this LinkedList<T> list) { 
     var node = list.Last; 
     while (node != null) { 
      yield return node.Value; 
      node = node.Previous; 
     } 
    } 
+1

Cảm ơn Hans, Great code! Nếu bạn muốn bạn có thể cập nhật mã của bạn với gần đây: IReadOnlyList. –

Các vấn đề liên quan