2009-06-04 3 views

Antwort

40

Ich denke, die in der Antwort verwiesene Dokumentation ist extrem irreführend. Die Reihenfolge von For Each wird durch die Sammlung definiert, die es genannt wird (d. H. Seine Implementierung von IEnumerable/IEnumerable<T>), aber das ist nicht das gleiche wie sagen, es sollte nicht verwendet werden, wenn die Reihenfolge wichtig ist. Viele Sammlungen (wie Arrays, List<T> usw.) gehen immer in der "natürlichen" Reihenfolge.

Teil der Dokumentation, auf diese nicht anspielen:

Traversierfolgeliste. Wenn Sie eine For Each ... Next-Schleife ausführen, wird das Durchlaufen der -Auflistung unter der Kontrolle des Enumeratorobjekts , das von der GetEnumerator-Methode zurückgegeben wird. Die Reihenfolge traversal wird nicht von Visual Basic, sondern von der MoveNext Methode des Enumerator-Objekts bestimmt. Diese bedeutet, dass Sie möglicherweise nicht in der Lage vorherzusagen, welches Element der Sammlung ist die erste, die in Element zurückgegeben wird, oder die nächste nach einem gegebenen Element zurückgegeben wird.

Das ist nicht bei allen das gleiche ist wie sagen, es kann sich nicht darauf verlassen - es auf verlassen können, wenn Sie wissen, dass die Sammlung Sie iterieren werden die Ergebnisse in der gewünschten Reihenfolge erzeugen. Es ist nicht so, als würde es Elemente zufällig auswählen. Das Verhalten in Bezug auf IEnumerable/IEnumerable<T> ist auf dieser Seite klar definiert.

Die wichtigsten Ausnahmen zu vorhersagbaren Ordnungen sind Wörterbücher und Mengen, die natürlich ungeordnet sind.

Um ein IEnumerable<T> verwenden Enumerable.Reverse zu umkehren - aber wenn Sie in umgekehrter Richtung über eine Sammlung iterieren müssen, die von Position (wie ein Array oder List<T>) indiziert ist, dann wäre es effizienter sein, eine For Schleife an dem Start zu verwenden, Ende und rückwärts arbeiten.

+3

Dank Jon, es ist immer ein Vergnügen, Ihre Eingabe und Einsicht zu erhalten: D – Anders

+1

Warum ist diese Antwort nicht die akzeptierte? Es Beispiele mehr indept –

+0

@DotNet Programmer: das war alte Post, dass ich erkannte, dass ich die REAL Antwort nicht zurück, wenn :) :) richtiges Kredit ist jetzt gegeben worden (nicht, dass Jon braucht mehr Punkte sowieso: P) – Anders

31

würden Sie haben, wie etwas zu tun:

For i as integer = myStringList.Count-1 to 0 step -1 
    dim s as string = myStringList.Item(i) 
    ' Do your stuff with s 
Next i 

Aber soweit ich weiß, kann man nicht tun, eine „For ... Jede“ rückwärts, aber das würde in ein paar schön Instanzen.

+0

genau benötigen. Ich habe nur dafür gesorgt, dass ich nicht auf ein cooles "verstecktes", auch nicht gut dokumentiertes Feature von VB verpasst habe. – Anders

+0

Das ist perfekt! – GunWanderer

13

Leider gibt MSDN docs on For Each an, dass das Konstrukt For Each explizit für Fälle vorhanden ist, in denen die Reihenfolge der Iteration unwichtig ist (ungeordnete Mengen und ähnliches). Es gibt also leider kein Konzept, ein For Each umzukehren, da die Reihenfolge ohnehin nicht definiert ist.

Viel Glück!

+1

Ich habe dies erwartet, aber ich war nicht 100% sicher, also danke für eine bestimmte keine w/Referenz als Bonus :) – Anders

+0

das ist richtig - ich nehme immer an, dass "For Each" Loops in Reihenfolge gehen, und während sie normalerweise tu, man kann sich nicht darauf verlassen. Wenn Sie eine bestimmte Reihenfolge wünschen, ist ein "For ... Next" für die Indizes im Array die einzige Wahl. – SqlRyan

+6

Sie können sich darauf verlassen *, wenn Sie wissen, dass die von Ihnen verwendete Sammlung in der richtigen Reihenfolge iteriert. Zum Beispiel werden Arrays * immer * in der natürlichen Reihenfolge durchlaufen. Siehe meine Antwort für weitere Details. –

10

Rufen Sie die System.Linq.Enumerable.Reverse Methode auf, um eine IEnuemrable(Of TSource) in der umgekehrten Reihenfolge Ihrer aufzählbaren Quelle zu erhalten.

+0

Ja, das muss ich am Ende machen. Vielen Dank! – Anders

+0

Ich hatte keine Ahnung, dass dies funktionierte, obwohl das MSDN-Beispiel das Array umgekehrt umkehrte und es dann mit einer "For Each" -Schleife aufruft, die bei einer bestimmten Reihenfolge nicht unbedingt verlässlich ist. Hoppla ... – SqlRyan

+3

alle foreach'able Typen implementieren GetEnumerator(). Einige Enumeratoren haben eine zuverlässige Reihenfolge, andere nicht. Da es sich hier um eine umgekehrte Reihenfolge handelt, besteht die Wahrscheinlichkeit, dass der Enumerator, mit dem wir es zu tun haben, eine zuverlässige Anweisung zum Rückgängigmachen hat. Natürlich erfüllen nicht alle Enumeratoren diese Kriterien. Enumeratoren für Arrays sind mit Sicherheit zuverlässig geordnet und reversibel. –

1

Der Grund, warum es nicht getan werden kann, ist, dass For Each als grundlegendes Design-Feature über ein Enumerable ohne ein letztes Element oder mit einem bis jetzt unbekannten letzten Element iterieren kann.

0

Was Sie tun müssen, ist ein Array mit Ihrem für jedes zuvor erstellen, dann verwenden Sie array.reverse und führen Sie die für jedes auf dem Array. Geschehen

Prost

+2

Hallo xxxmandoxxx. Bevor Sie eine Antwort hinzufügen, sollten Sie prüfen, ob die gleiche Antwort bereits existiert. Ihre Antwort erhöht den Wert des Posts nicht. – stenci

0

Je nachdem, was in Ihrer Schleife geschah können Sie eine .InsertAt tun (Objekt, 0) anstelle ein .Add und produzieren das gleiche Ergebnis wie eine umgekehrte Aufzählung.

3
For Each s As String In myStringList.Reverse 
    //' Do stuff here 
Next 
3

Testig in Framework 4, der Code

For Each s As String In myStringList.Reverse 
    //' Do stuff here 
Next 

es nicht funktioniert, ist der richtige Weg, es zu tun ist:

myStringList.Reverse() ' it is a method not a function 
For Each s As String In myStringList 
//' Do stuff here 
Next 

Blick auf: MSDN: Reserve

+0

Es funktioniert auch in generischen Listen – Dave

0

Sie können der Klasse, die Sie umkehren möchten, eine erweiterte Funktion hinzufügen

<Serializable()> Public Class SomeCollection 
    Inherits CollectionBase 
    Public Sub New() 
    End Sub 

    Public Sub Add(ByVal Value As Something) 
     Me.List.Add(Value) 
    End Sub 

    Public Sub Remove(ByVal Value As Something) 
     Me.List.Remove(Value) 
    End Sub 

    Public Function Contains(ByVal Value As Something) As Boolean 
     Return Me.List.Contains(Value) 
    End Function 

    Public Function Item(ByVal Index As Integer) As Something 
     Return DirectCast(Me.List.Item(Index), Something) 
    End Function 

    Public Function Reverse() As SomeCollection 
     Dim revList As SomeCollection = New SomeCollection() 
     For index As Integer = (Me.List.Count - 1) To 0 Step -1 
      revList.List.Add(Me.List.Item(index)) 
     Next 
     Return revList 
    End Function 
End Class 

Dann würden Sie es wie nennen dieses

For Each s As Something In SomeCollection.Reverse 

Next 
0

zuerst sollten Sie eine Liste erstellen (von string) in für jede Anweisung, und danach einen anderen normalen machen .. Schritt -1 ..next Erklärung. siehe Beispiel:

Dim ff As New List(Of Integer) 
For Each rRow As DataRow In DeletedRows 
Dim item As Integer 
item = rRow.Table.Rows.IndexOf(rRow) 
ff.Add(item) 
Next 
For i As Integer = ff.Count - 1 To 0 Step -1 
dim item as integer=ff(i) 
next i 

Ich hoffe, diese Antwort hilfreich sein

0

Die akzeptierte erklärt, warum, aber ein weiteres Beispiel an, für eine Sammlung mit Schlüssel (SortedList, SortedDictionary, Wörterbuch, etc.) Sie tun können

For Each Id as Tkey in MyCollection.Keys.Reverse 
    // The item in question is now available as MyCollection(Id) 
Next 
0

'eine Liste von was auch immer erstellen und For-Schleife Schritt durch Sammeln

dim revList as New List (of ToolStripItem) 
For each objItem as ToolStripItem in Menu.DropDownItems 
    revList.Add(objItem) 
next 
revList.reverse ' reverse the order of that list 

'Schritt für Schritt durch die umgekehrte geordnete Liste

for each objItem as ToolStripItem in revList 
    ' do whatever (like removing your menu from an ArrayMenu) 
next 

' ersetzen ToolStripItem und Menu.DropDownItems mit dem, was Sie