2012-02-17 15 views
16

¿Alguien sabe si hubo una razón específica o decisión de diseño para no incluir un enumerador reverso en C#? Sería tan bueno si hubiera un equivalente al C++ reverse_iterator, al igual que el Enumerador es el equivalente del C++ iterator. Colecciones que se pueden repetir-inversa se acaba de poner en práctica algo así como IReverseEnumerable y se podría hacer algo como:¿Por qué no hay ReverseEnumerator en C#?

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

esta manera, usted sería capaz de recorrer listas y LinkedLists de la misma manera en lugar de utilizar paso a paso para uno y enlaces previos para el otro logrando así una mejor abstracción

+1

Interesante pregunta, 'MoveNext()' parece un poco una contradicción para un empadronador inversa aunque supongo que para la compatibilidad con '' foreach' la GetReverseEnumerator() 'método sería en realidad todavía tienen que devolver un 'IEnumerator' y por lo tanto requeriría ese método, incluso si' MovePrevious() 'parece más apropiado para mi mente – RobV

+2

Existe el método de extensión Reverse linq que logra algo similar ... – RQDQ

+3

En los tipos que implementan' IList 'obtenemos un 'Reverse' eficiente de linq. Lamentablemente, no todos los tipos que pueden implementar 'Reverse' de manera eficiente, también pueden implementar' IList '. Por ejemplo, una lista doblemente vinculada. Así que estoy de acuerdo en que esas colecciones que tengan un método 'Reverse()' incorporado, serían agradables. – CodesInChaos

Respuesta

21

Sería completamente posible implementar esto. Personalmente, casi nunca hago iteraciones inversas. Si necesito hacer esto, llamo .Reverse() primero. Probablemente esto es lo que los diseñadores .NET BCL también pensaron.

Todas las características no se implementan por defecto. Deben diseñarse, implementarse, probarse, documentarse y respaldarse. - Raymond Chen

Y es por esto que no se implementa características que proporcionan poca utilidad. Comienzas con las características más importantes (como iterar de adelante hacia atrás). Y te detienes en un lugar donde tu presupuesto se agota o donde crees que no tiene sentido continuar.

Hay muchas cosas que no están en la biblioteca de clases base de .NET. Hasta .NET 4 ni siquiera era un File.EnumerateLines. Y me atrevería a decir que tal funcionalidad es más importante que la iteración inversa para la mayoría de las personas.

Puede ser que esté trabajando en un dominio comercial donde la iteración inversa es común. Mi experiencia es lo opuesto. Como diseñador de marcos, solo puede adivinar quién utilizará su marco y qué características exigirán estas personas. Es difícil trazar la línea.

+2

¿No se llama 'File.ReadLines'? – nawfal

11

No está disponible porque IEnumerable es un iterador de solo reenvío. Solo tiene un método MoveNext(). Eso hace que la interfaz sea muy universal y el núcleo de Linq. Hay muchas colecciones del mundo real que no se pueden repetir al revés porque eso requiere almacenamiento. La mayoría de las transmisiones son así, por ejemplo.

Linq proporciona una solución con el método de extensión Reverse(). Funciona al almacenar los elementos primero, y luego iterarlos hacia atrás. Sin embargo, eso puede ser muy inútil, requiere O (n) almacenamiento. Falta una posible optimización para colecciones que ya son indexables. Que se puede solucionar: el uso

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]; 
      } 
     } 
    } 
} 

muestra:

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

Usted querrá hacer una especialización para LinkedList ya que no implementa IList <> pero todavía permite rápida hacia atrás iteración a través de la Última y propiedades LinkedListNode.Previous. Aunque es mucho mejor no usar esa clase, tiene una ubicación de caché de CPU pésima. Siempre favor de la Lista <> cuando no necesite inserciones baratas.Se podría tener este aspecto:

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

Gracias Hans, ¡Gran código! Si lo desea, puede actualizar su código con el último: IReadOnlyList. –

Cuestiones relacionadas