Frage

Ich weiß, ich könnte eine for Anweisung verwenden und die gleiche Wirkung erzielen, aber kann ich Schleife rückwärts durch eine foreach Schleife in C #?

War es hilfreich?

Lösung

Wenn Sie mit einer Liste (direkte Indizierung) arbeiten, können Sie es nicht tun, so effizient wie eine for Schleife.

Edit: Was bedeutet in der Regel, wenn Sie können eine for Schleife zu verwenden, ist es wahrscheinlich die richtige Methode für diese Aufgabe. Plus, für so viel wie foreach ist in Ordnung implementiert, das Konstrukt selbst auszudrücken Schleifen aufgebaut ist, die von Element-Indizes unabhängig sind und Iterationsreihenfolge, was besonders wichtig ist in parallele Programmierung . Es ist meiner Meinung nach , die Iteration auf, um unter Berufung nicht foreach für Looping.

verwenden sollten

Andere Tipps

Wenn Sie auf .NET 3.5 sind Sie können dies tun:

IEnumerable<int> enumerableThing = ...;
foreach (var x in enumerableThing.Reverse())

Es ist nicht sehr effizient, da es im Grunde gehen durch den enumerator nach vorne hat auf einem Stapel alles setzt dann alles wieder aus in umgekehrter Reihenfolge erscheint.

Wenn Sie eine direkt-Wendesammlung (z IList) Sie sollten auf jeden Fall eine for Schleife verwenden, statt.

Wenn Sie auf .NET 2.0 und kann nicht eine for-Schleife verwenden (das heißt Sie müssen nur ein IEnumerable), dann müssen Sie nur noch Ihre eigene Reverse-Funktion schreiben. Dies sollte funktionieren:

static IEnumerable<T> Reverse<T>(IEnumerable<T> input)
{
    return new Stack<T>(input);
}

Dieses stützt sich auf einige Verhaltensweisen, die vielleicht nicht so offensichtlich ist. Wenn Sie in einem IEnumerable in dem Stapel Konstruktor übergeben wird es durchlaufen und die Elemente auf den Stapel schieben. Wenn Sie dann durch den Stapel durchlaufen knallt es Dinge wieder aus in umgekehrter Reihenfolge.

Dies und die .NET 3.5 Reverse() Erweiterungsmethode wird natürlich die Luft sprengen, wenn Sie ihm ein IEnumerable füttern, die nie zurückgehende Einzelteile stoppen.

Wie 280Z28 sagt, für eine IList<T> können Sie nur den Index verwenden. Man könnte dies in einer Erweiterungsmethode verbergen:

public static IEnumerable<T> FastReverse<T>(this IList<T> items)
{
    for (int i = items.Count-1; i >= 0; i--)
    {
        yield return items[i];
    }
}

Dies wird schneller sein als Enumerable.Reverse(), die die Daten aller ersten Puffer. (Ich glaube nicht, Reverse keine Optimierungen in der Art und Weise angewandt hat, dass Count() der Fall ist.) Beachten Sie, dass diese Pufferung bedeutet, dass die Daten vollständig gelesen wird, wenn Sie zum ersten Mal das Iterieren beginnen, während FastReverse „sehen“ alle auf der Liste vorgenommenen Änderungen, während Sie iterieren. (Es wird auch brechen, wenn Sie mehrere Elemente zwischen Iterationen entfernen.)

Für allgemeine Sequenzen, es gibt keinen Weg in umgekehrter Richtung von Iterieren - die Folge unendlich sein könnte, zum Beispiel:

public static IEnumerable<T> GetStringsOfIncreasingSize()
{
    string ret = "";
    while (true)
    {
        yield return ret;
        ret = ret + "x";
    }
}

Was möchten Sie passieren erwarten, wenn Sie, dass in umgekehrter Reihenfolge iterieren versucht?

Vor 'foreach' für Iteration verwendet wird, kehren die Liste der 'umgekehrten' Methode:

    myList.Reverse();
    foreach( List listItem in myList)
    {
       Console.WriteLine(listItem);
    }

Wenn Sie eine Liste verwenden, können Sie auch diesen Code verwenden:

List<string> list = new List<string>();
list.Add("1");
list.Add("2");
list.Add("3");
list.Reverse();

Dies ist ein Verfahren, das die Liste umgekehrt in sich selbst schreiben.

Nun ist die foreach:

foreach(string s in list)
{
    Console.WriteLine(s);
}

Die Ausgabe lautet:

3
2
1

Manchmal hat man nicht den Luxus der Indizierung, oder vielleicht wollen Sie die Ergebnisse einer Abfrage Linq rückgängig zu machen, oder vielleicht möchten Sie nicht die Quellensammlung ändern, wenn eine dieser Bedingungen erfüllt sind, kann Linq helfen Sie.

Eine Linq-Erweiterungsmethode anonyme Typen mit Linq Wählen Sie mit einem Sortierschlüssel für Linq OrderByDescending bereitzustellen;

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

Verbrauch:

    var eable = new[]{ "a", "b", "c" };

    foreach(var o in eable.Invert())
    {
        Console.WriteLine(o);
    }

    // "c", "b", "a"

Es heißt „Invert“, weil es mit „Reverse“ ist ein Synonym für und ermöglicht Begriffsklärung mit der List-Reverse-Implementierung.

Es ist möglich, bestimmte Bereiche von einer Sammlung zu umkehren, da Int32.MinValue und Int32.MaxValue aus dem Bereich von jeder Art von Sammlung Index sind, können wir sie für den Bestellprozess nutzen können; Wenn ein Element-Index unter dem angegebenen Bereich ist, wird es zugeordnet Int32.MaxValue so dass seine Bestellung nicht ändert, wenn OrderByDescending verwendet wird, in ähnlicher Weise, Elemente bei einem Index größer als der gegebene Bereich ist, zugeordnet Int32.MinValue werden, so dass sie erscheinen am Ende des Bestellprozesses. Alle Elemente innerhalb des angegebenen Bereichs sind ihre normalen Index zugeordnet und entsprechend umgekehrt.

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

Verbrauch:

    var eable = new[]{ "a", "b", "c", "d" };

    foreach(var o in eable.Invert(1, 2))
    {
        Console.WriteLine(o);
    }

    // "a", "c", "b", "d"

Ich bin die Performance-Hits dieser Linq-Implementierungen nicht sicher, ob eine temporäre Liste im Vergleich mit einer Sammlung wickeln für die Umkehr.


Zum Zeitpunkt des Schreibens, ich war nicht bewusst, Linq eigenen Reverse-Implementierung, noch war es Spaß bei der Arbeit dies. https://msdn.microsoft.com/ en-us / library / VStudio / bb358497 (v = VS.100) aspx

Nein. ForEach gerade iteriert durch Sammlung für jedes Element und Ordnung abhängt, ob es verwendet IEnumerable oder GetEnumerator ().

Es ist möglich, wenn Sie den Sammlungscode ändern , die IEnumerable oder IEnumerable implementiert (zum Beispiel eine eigene Implementierung von IList).

Erstellen Sie eine Iterator macht diese Arbeit für Sie, zum Beispiel, wie die folgenden Umsetzung durch die IEnumerable Schnittstelle (unter der Annahme 'Elemente' ist ein Listenfeld in diesem Beispiel):

public IEnumerator<TObject> GetEnumerator()
{
    for (var i = items.Count - 1; i >= 0; i--)
    { 
        yield return items[i];
    }
}

IEnumerator IEnumerable.GetEnumerator()
{
    return GetEnumerator();
}

Aus diesem Grunde Ihre Liste wird in umgekehrter Reihenfolge durch die Liste durchlaufen.

Nur ein Hinweis: Sie sollten klar dieses besondere Verhalten Ihrer Liste angeben, in der Dokumentation (besser noch durch ein selbsterklärende Klassennamen wie Stapel oder Queue Auswahl, auch)

.

Elaborateling slighty auf die nette Antwort von Jon Skeet , diese vielseitig sein könnte:

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

Und dann verwenden, wie

foreach (var item in myList.Directional(forwardsCondition)) {
    .
    .
}

Ich habe diesen Code verwendet, die gearbeitet

                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) {

Das funktioniert ziemlich gut

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]);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top