Sé que podría usar una for
declaración y lograr el mismo efecto, pero ¿puedo recorrer hacia atrás a través de un foreach
ciclo en C #?
IEnumerable<int> Infinity() { int i = 1; while (true) yield return i++; }
¿Cómo revertiría eso?
Sé que podría usar una for
declaración y lograr el mismo efecto, pero ¿puedo recorrer hacia atrás a través de un foreach
ciclo en C #?
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 que foreach
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 usarse foreach
para el bucle.
yield return
".
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 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:
static IEnumerable<T> Reverse<T>(IEnumerable<T> input)
{
return new Stack<T>(input);
}
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.
Como dice 280Z28, para un IList<T>
solo puede usar el índice. Puede ocultar esto en un método de extensión:
public static IEnumerable<T> FastReverse<T>(this IList<T> items)
{
for (int i = items.Count-1; i >= 0; i--)
{
yield return items[i];
}
}
Esto será más rápido que lo Enumerable.Reverse()
que almacena primero todos los datos. (No creo que Reverse
haya 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 FastReverse
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:
public static IEnumerable<T> GetStringsOfIncreasingSize()
{
string ret = "";
while (true)
{
yield return ret;
ret = ret + "x";
}
}
¿Qué esperarías que pasara si intentaras iterar sobre eso a la inversa?
Antes de usar foreach
para la iteración, invierta la lista por el reverse
método:
myList.Reverse();
foreach( List listItem in myList)
{
Console.WriteLine(listItem);
}
myList
que será será útil. IEnumerable. Inversa no funcionará aquí.
myList
parece ser de tipo System.Collections.Generic.List<System.Windows.Documents.List>
(o cualquier otro List
tipo personalizado ) de lo contrario, este código no funciona: P
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;
public static IEnumerable<T> Invert<T>(this IEnumerable<T> source)
{
var transform = source.Select(
(o, i) => new
{
Index = i,
Object = o
});
return transform.OrderByDescending(o => o.Index)
.Select(o => o.Object);
}
Uso:
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.
public static IEnumerable<T> Invert<T>(this IEnumerable<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.
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
Si usa una Lista <T>, también puede usar este código:
List<string> list = new List<string>();
list.Add("1");
list.Add("2");
list.Add("3");
list.Reverse();
Este es un método que escribe la lista inversa en sí misma.
Ahora el foreach:
foreach(string s in list)
{
Console.WriteLine(s);
}
El resultado es:
3
2
1
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):
public IEnumerator<TObject> GetEnumerator()
{
for (var i = items.Count - 1; i >= 0; i--)
{
yield return items[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
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).
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 ().
Explicando ligeramente la buena respuesta de Jon Skeet , esto podría ser versátil:
public static IEnumerable<T> Directional<T>(this IList<T> items, bool Forwards) {
if (Forwards) foreach (T item in items) yield return item;
else for (int i = items.Count-1; 0<=i; i--) yield return items[i];
}
Y luego usar como
foreach (var item in myList.Directional(forwardsCondition)) {
.
.
}
He usado este código que funcionó
if (element.HasAttributes) {
foreach(var attr in element.Attributes().Reverse())
{
if (depth > 1)
{
elements_upper_hierarchy_text = "";
foreach (var ancest in element.Ancestors().Reverse())
{
elements_upper_hierarchy_text += ancest.Name + "_";
}// foreach(var ancest in element.Ancestors())
}//if (depth > 1)
xml_taglist_report += " " + depth + " " + elements_upper_hierarchy_text+ element.Name + "_" + attr.Name +"(" + attr.Name +")" + " = " + attr.Value + "\r\n";
}// foreach(var attr in element.Attributes().Reverse())
}// if (element.HasAttributes) {
.Reverse()
realidad está modificando la lista.
Esto funciona bastante bien
List<string> list = new List<string>();
list.Add("Hello");
list.Add("Who");
list.Add("Are");
list.Add("You");
foreach (String s in list)
{
Console.WriteLine(list[list.Count - list.IndexOf(s) - 1]);
}