Tendría que crear instancias de todos los elementos en la enumeración para poder revertir su orden. Puede que no sea posible. Considere la secuencia: IEnumerable<int> Infinity() { int i = 1; while (true) yield return i++; }¿Cómo revertiría eso?
Suncat2000
Respuestas:
84
Al trabajar con una lista (indexación directa), no puede hacerlo de manera tan eficiente como usar un forbucle.
Editar: lo que generalmente significa que, cuando puede usar un forbucle, es probable que sea el método correcto para esta tarea. Además, en la medida en que foreachse implementa en orden, la construcción en sí misma se construye para expresar bucles que son independientes de los índices de elementos y el orden de iteración, lo cual es particularmente importante en la programación paralela . En mi opinión, la iteración que se basa en el orden no debería usarse foreachpara el bucle.
Su última declaración me parece demasiado general. Seguramente hay casos en los que, por ejemplo, un IEnumerable de algún tipo debe iterarse en orden. ¿No usarías foreach en ese caso? ¿Qué usarías?
avl_sweden
1
ACTUALIZACIÓN: Consulte [la respuesta de Bryan a una pregunta similar [( stackoverflow.com/a/3320924/199364 ), para obtener una respuesta más moderna, utilizando Linq y discutiendo ambas listas y otros enumerables.
ToolmakerSteve
ACTUALIZACIÓN: Jon Skeet tiene una respuesta aún más elegante, que ahora es posible, usando " yield return".
ToolmakerSteve
2
Tuve la misma reacción inicial que @avl_sweden: "la iteración basada en el orden no debe usar foreach" suena demasiado general. Sí, foreach es bueno para expresar tareas paralelas independientes del orden. PERO también es una parte esencial de la programación moderna basada en iteradores . Quizás el punto es que sería más claro / seguro si hubiera dos palabras clave distintas , para aclarar si uno está afirmando que las iteraciones son independientes del orden. [Dado un lenguaje como Eiffel que puede propagar contratos, tales afirmaciones pueden ser demostrablemente verdaderas o falsas, para un código dado.]
ToolmakerSteve
2
La idea de que foreach "se construye para expresar bucles que son independientes de los índices de elementos y el orden de iteración" es incorrecta. La especificación del lenguaje c # requiere que cada elemento del proceso esté en orden. Ya sea utilizando MoveNext en iteradores o procesando índices que comienzan en cero y se incrementan en uno en cada iteración de matrices.
Donald Rich
145
Si está en .NET 3.5 puede hacer esto:
IEnumerable<int> enumerableThing =...;foreach(var x in enumerableThing.Reverse())
No es muy eficiente, ya que básicamente tiene que pasar por el enumerador hacia adelante colocando todo en una pila y luego vuelve a mostrar todo en orden inverso.
Si tiene una colección indexable directamente (por ejemplo, IList), definitivamente debería usar un forbucle.
Si está en .NET 2.0 y no puede usar un bucle for (es decir, solo tiene un IEnumerable), entonces solo tendrá que escribir su propia función inversa. Esto debería funcionar:
Esto se basa en un comportamiento que quizás no sea tan obvio. Cuando pasa un IEnumerable al constructor de la pila, iterará a través de él y empujará los elementos a la pila. Cuando iteras a través de la pila, las cosas vuelven a aparecer en orden inverso.
Reverse()Obviamente, este y el método de extensión .NET 3.5 explotarán si lo alimenta con un IEnumerable que nunca deja de devolver elementos.
¿Me estoy perdiendo algo o su solución .Net 3.5 no funciona realmente? Reverse () invierte la lista en su lugar y no la devuelve. Lástima, ya que esperaba una solución como esa.
usuario12861
2
Algunos administradores marcan esta respuesta como INCORRECTA por favor. Reverse () es un vacío [1] y, por lo tanto, el ejemplo anterior conduce a un error de compilación. [1] msdn.microsoft.com/en-us/library/b0axc2h2(v=vs.110).aspx
MickyD
66
@ user12861, Micky Duncan: la respuesta no es incorrecta, te falta algo. Hay un método inverso en System.Collections.Generic.List <T> que hace un reverso in situ. En .Net 3.5 hay un método de extensión en IEnumerable <T> llamado Reverse. He cambiado el ejemplo de var a IEnumerable <int> para hacerlo más explícito.
Matt Howells
55
Como dice 280Z28, para un IList<T>solo puede usar el índice. Puede ocultar esto en un método de extensión:
publicstaticIEnumerable<T>FastReverse<T>(thisIList<T> items){for(int i = items.Count-1; i >=0; i--){yieldreturn items[i];}}
Esto será más rápido que lo Enumerable.Reverse()que almacena primero todos los datos. (No creo que Reversehaya ninguna optimización aplicada de la manera que lo Count()hace). Tenga en cuenta que este almacenamiento en búfer significa que los datos se leen completamente cuando comienza a iterar por primera vez, mientras FastReverseque "verá" cualquier cambio realizado en la lista mientras itera. (También se romperá si elimina varios elementos entre iteraciones).
Para secuencias generales, no hay forma de iterar en reversa: la secuencia podría ser infinita, por ejemplo:
publicstaticIEnumerable<T>GetStringsOfIncreasingSize(){string ret ="";while(true){yieldreturn ret;
ret = ret +"x";}}
¿Qué esperarías que pasara si intentaras iterar sobre eso a la inversa?
Solo curiosidad, ¿por qué usar "> = 0" en lugar de "> -1"?
Chris S
15
> ¿por qué usar "> = 0" en lugar de "> -1"? Porque> = 0 comunica mejor la intención a los humanos que leen el código. El compilador debería poder optimizar eso al equivalente> -1 si hacerlo mejoraría el rendimiento.
Mark Maslar
1
FastReverse (estos elementos IList <T>) deben ser FastReverse <T> (estos elementos IList <T>. :)
Rob
Dividir los palos 0 <= i es aún mejor. Después de enseñar un buen número de matemáticas a los niños a lo largo de los años y ayudar a las personas con la codificación, descubrí que reduce mucho los errores que cometen las personas si SIEMPRE intercambian a> b a b <a como las cosas van en el orden natural de una línea de números (o el eje X de un sistema de coordenadas): el único inconveniente es si necesita pegar una ecuación en XML, digamos un .config
Eske Rahn
13
Antes de usar foreachpara la iteración, invierta la lista por el reversemétodo:
myList.Reverse();foreach(List listItem in myList){Console.WriteLine(listItem);}
Una palabra de precaución sobre lo myListque será será útil. IEnumerable. Inversa no funcionará aquí.
nawfal
2
@ MA-Maddin no, los dos son diferentes. Supongo que el respondedor confía en la Lista <T>. Inversa que está en su lugar.
nawfal
En realidad, no sé por qué dije eso. Debería haber agregado más detalles ... De todos modos, este es un código confuso ya que myListparece ser de tipo System.Collections.Generic.List<System.Windows.Documents.List>(o cualquier otro Listtipo personalizado ) de lo contrario, este código no funciona: P
Martin Schneider
5
A veces no tiene el lujo de indexar, o tal vez desee revertir los resultados de una consulta de Linq, o tal vez no desee modificar la colección de origen, si alguno de estos es cierto, Linq puede ayudarlo.
Un método de extensión de Linq que utiliza tipos anónimos con Linq Select para proporcionar una clave de clasificación para Linq OrderByDescending;
var eable =new[]{"a","b","c"};foreach(var o in eable.Invert()){Console.WriteLine(o);}// "c", "b", "a"
Se llama "Invertir" porque es sinónimo de "Reversa" y permite la desambiguación con la implementación Lista inversa.
También es posible revertir ciertos rangos de una colección, ya que Int32.MinValue e Int32.MaxValue están fuera del rango de cualquier tipo de índice de colección, podemos aprovecharlos para el proceso de pedido; si un índice de elemento está por debajo del rango dado, se le asigna Int32.MaxValue para que su orden no cambie cuando se usa OrderByDescending, de manera similar, los elementos en un índice mayor que el rango dado, se asignarán Int32.MinValue, de modo que aparecer al final del proceso de pedido. A todos los elementos dentro del rango dado se les asigna su índice normal y se invierten en consecuencia.
publicstaticIEnumerable<T>Invert<T>(thisIEnumerable<T> source,int index,int count){var transform = source.Select((o, i)=>new{Index= i < index ?Int32.MaxValue: i >= index + count ?Int32.MinValue: i,Object= o
});return transform.OrderByDescending(o => o.Index).Select(o => o.Object);}
Uso:
var eable =new[]{"a","b","c","d"};foreach(var o in eable.Invert(1,2)){Console.WriteLine(o);}// "a", "c", "b", "d"
No estoy seguro de los éxitos de rendimiento de estas implementaciones de Linq en comparación con el uso de una lista temporal para envolver una colección para revertirla.
Es posible si puede cambiar el código de recopilación que implementa IEnumerable o IEnumerable (por ejemplo, su propia implementación de IList).
Cree un iterador que haga este trabajo por usted, por ejemplo, como la siguiente implementación a través de la interfaz IEnumerable (suponiendo que 'elementos' es un campo de lista en este ejemplo):
publicIEnumerator<TObject>GetEnumerator(){for(var i = items.Count-1; i >=0; i--){yieldreturn items[i];}}IEnumeratorIEnumerable.GetEnumerator(){returnGetEnumerator();}
Debido a esto, su Lista iterará en orden inverso a través de su lista.
Solo una pista: debe indicar claramente este comportamiento especial de su lista dentro de la documentación (incluso mejor eligiendo un nombre de clase autoexplicativo como Stack o Queue, también).
Esto es malo porque en .Reverse()realidad está modificando la lista.
Colin Basnett
-8
Esto funciona bastante bien
List<string>list=newList<string>();list.Add("Hello");list.Add("Who");list.Add("Are");list.Add("You");foreach(String s inlist){Console.WriteLine(list[list.Count-list.IndexOf(s)-1]);}
IEnumerable<int> Infinity() { int i = 1; while (true) yield return i++; }
¿Cómo revertiría eso?Respuestas:
Al trabajar con una lista (indexación directa), no puede hacerlo de manera tan eficiente como usar un
for
bucle.Editar: lo que generalmente significa que, cuando puede usar un
for
bucle, es probable que sea el método correcto para esta tarea. Además, en la medida en queforeach
se implementa en orden, la construcción en sí misma se construye para expresar bucles que son independientes de los índices de elementos y el orden de iteración, lo cual es particularmente importante en la programación paralela . En mi opinión, la iteración que se basa en el orden no debería usarseforeach
para el bucle.fuente
yield return
".Si está en .NET 3.5 puede hacer esto:
No es muy eficiente, ya que básicamente tiene que pasar por el enumerador hacia adelante colocando todo en una pila y luego vuelve a mostrar todo en orden inverso.
Si tiene una colección indexable directamente (por ejemplo, IList), definitivamente debería usar un
for
bucle.Si está en .NET 2.0 y no puede usar un bucle for (es decir, solo tiene un IEnumerable), entonces solo tendrá que escribir su propia función inversa. Esto debería funcionar:
Esto se basa en un comportamiento que quizás no sea tan obvio. Cuando pasa un IEnumerable al constructor de la pila, iterará a través de él y empujará los elementos a la pila. Cuando iteras a través de la pila, las cosas vuelven a aparecer en orden inverso.
Reverse()
Obviamente, este y el método de extensión .NET 3.5 explotarán si lo alimenta con un IEnumerable que nunca deja de devolver elementos.fuente
Como dice 280Z28, para un
IList<T>
solo puede usar el índice. Puede ocultar esto en un método de extensión:Esto será más rápido que lo
Enumerable.Reverse()
que almacena primero todos los datos. (No creo queReverse
haya ninguna optimización aplicada de la manera que loCount()
hace). Tenga en cuenta que este almacenamiento en búfer significa que los datos se leen completamente cuando comienza a iterar por primera vez, mientrasFastReverse
que "verá" cualquier cambio realizado en la lista mientras itera. (También se romperá si elimina varios elementos entre iteraciones).Para secuencias generales, no hay forma de iterar en reversa: la secuencia podría ser infinita, por ejemplo:
¿Qué esperarías que pasara si intentaras iterar sobre eso a la inversa?
fuente
Antes de usar
foreach
para la iteración, invierta la lista por elreverse
método:fuente
myList
que será será útil. IEnumerable. Inversa no funcionará aquí.myList
parece ser de tipoSystem.Collections.Generic.List<System.Windows.Documents.List>
(o cualquier otroList
tipo personalizado ) de lo contrario, este código no funciona: PA veces no tiene el lujo de indexar, o tal vez desee revertir los resultados de una consulta de Linq, o tal vez no desee modificar la colección de origen, si alguno de estos es cierto, Linq puede ayudarlo.
Un método de extensión de Linq que utiliza tipos anónimos con Linq Select para proporcionar una clave de clasificación para Linq OrderByDescending;
Uso:
Se llama "Invertir" porque es sinónimo de "Reversa" y permite la desambiguación con la implementación Lista inversa.
También es posible revertir ciertos rangos de una colección, ya que Int32.MinValue e Int32.MaxValue están fuera del rango de cualquier tipo de índice de colección, podemos aprovecharlos para el proceso de pedido; si un índice de elemento está por debajo del rango dado, se le asigna Int32.MaxValue para que su orden no cambie cuando se usa OrderByDescending, de manera similar, los elementos en un índice mayor que el rango dado, se asignarán Int32.MinValue, de modo que aparecer al final del proceso de pedido. A todos los elementos dentro del rango dado se les asigna su índice normal y se invierten en consecuencia.
Uso:
No estoy seguro de los éxitos de rendimiento de estas implementaciones de Linq en comparación con el uso de una lista temporal para envolver una colección para revertirla.
Al momento de escribir, no estaba al tanto de la implementación inversa de Linq, aún así, fue divertido resolver esto. https://msdn.microsoft.com/en-us/library/vstudio/bb358497(v=vs.100).aspx
fuente
Si usa una Lista <T>, también puede usar este código:
Este es un método que escribe la lista inversa en sí misma.
Ahora el foreach:
El resultado es:
fuente
Es posible si puede cambiar el código de recopilación que implementa IEnumerable o IEnumerable (por ejemplo, su propia implementación de IList).
Cree un iterador que haga este trabajo por usted, por ejemplo, como la siguiente implementación a través de la interfaz IEnumerable (suponiendo que 'elementos' es un campo de lista en este ejemplo):
Debido a esto, su Lista iterará en orden inverso a través de su lista.
Solo una pista: debe indicar claramente este comportamiento especial de su lista dentro de la documentación (incluso mejor eligiendo un nombre de clase autoexplicativo como Stack o Queue, también).
fuente
No. ForEach simplemente itera a través de la colección para cada artículo y el orden depende de si usa IEnumerable o GetEnumerator ().
fuente
Explicando ligeramente la buena respuesta de Jon Skeet , esto podría ser versátil:
Y luego usar como
fuente
He usado este código que funcionó
fuente
.Reverse()
realidad está modificando la lista.Esto funciona bastante bien
fuente