views:

1552

answers:

8

I don't believe this is possible by conventional methods, but something like this verbose code:

For Each s As String In myStringList Step -1
    //' Do stuff here
Next

I will probably have to invert the myString object before a conventional For..Each Loop, correct?

+5  A: 

You'd have to do something like:

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

But as far as I know, you can't do a "For...Each" backwards, though that would be nice in a few instances.

rwmnau
Exactly. I was just making sure I wasn't missing out on some cool 'hidden', aka not-well-documented, feature of VB.
Anders
+10  A: 

Sadly, the MSDN docs on For Each state that the For Each construct is there explicitly for cases where the order of the iteration is unimportant (unordered sets and the like). So there is unfortunately no concept of reversing a For Each, as the order is not defined anyway.

Good luck!

Mike
I was expecting this but I wasn't 100% sure, so thanks for a definite no w/ reference as a bonus :)
Anders
this is correct - I always assume that "For Each" loops go in order, and while they usually do, it can't be relied on. If you want a particular order, a "For...Next" on on of the indices in the array is your only choice.
rwmnau
It *can* be relied upon if you know the collection you're using iterates in the right order. For example, arrays will *always* iterate in the natural order. See my answer for more details.
Jon Skeet
(Downvoted as the claim that "the order is not defined anyway" is wrong - it's defined by the collection itself.)
Jon Skeet
The MSDN page Mike has linked confirms what Jon Skeet says [it wouldn't dare do otherwise] - the section "The order of traversal is not determined by Visual Basic, but rather by the MoveNext method of the enumerator object.". So the order *is* defined, but by the collection being iterated, not by the For Each statement itself.
MarkJ
thx for the clarification :)
Mike
i should point out though that if your IEnumerable implementation does not define an order, then For Each won't impose one.
Mike
+5  A: 

Call the Reverse method. http://msdn.microsoft.com/en-us/library/bb358497.aspx

David B
Yeah, that is what I will have to end up doing. Thanks!
Anders
I had no idea this worked, though oddly enough, the MSDN example reversed the array and then proceeds to walk it using a "For Each" loop, which is explicitly not dependable when a particular order is required. Oops...
rwmnau
all foreach'able types implement GetEnumerator(). Some Enumerators have reliable ordering and some don't. Since we are talking about reversed order, odds are that the Enumerator that we're dealing with has reliable ordering to reverse. Of course, not all Enumerators meet this criteria. Enumerators for Arrays, most certainly, are reliably ordered and reversable.
David B
A: 

The reason it can't be done is that, as a basic design feature, For Each can iterate over an enumerable without a last element, or with an as yet unknown last element.

reinierpost
A: 

You could convert the String to a Character Array and then reverse the array.

mamboking
+16  A: 

I think the documentation referenced in the answer is extremely misleading. The order of For Each is defined by the collection it's called (i.e. its implementation of IEnumerable/IEnumerable<T>), but that's not the same as saying it shouldn't be used when the order is important. Many collections (such as arrays, List<T> etc) always go in the "natural" order.

Part of the documentation does allude to this:

Traversal Order. When you execute a For Each...Next loop, traversal of the collection is under the control of the enumerator object returned by the GetEnumerator method. The order of traversal is not determined by Visual Basic, but rather by the MoveNext method of the enumerator object. This means that you might not be able to predict which element of the collection is the first to be returned in element, or which is the next to be returned after a given element.

That's not at all the same as saying it can't be relied upon - it can be relied upon if you know that the collection you're iterating over will produce the results in the desired order. It's not like it's going to pick elements at random. The behaviour in terms of IEnumerable/IEnumerable<T> is clearly defined on that page.

The most important exceptions to predictable orderings are dictionaries and sets, which are naturally unordered.

To reverse an IEnumerable<T>, use Enumerable.Reverse - but if you need to iterate in reverse over a collection which is indexed by position (such as an array or List<T>) then it would be more efficient to use a For loop starting at the end and working backwards.

Jon Skeet
Thanks Jon, it is always a pleasure to get your input and insight :D
Anders
A: 

How about use a Queue or First in Last Out collection?

rball
A: 

Just a thougth, you can create your own collection that uses a custom enumerator that iteracts that way you expect.

jamerson