views:

171

answers:

5

Is it possible to have a foreach statement that will traverse through a Collections object in reverse order?

If not a foreach statement is there any other way? Thanks.

+9  A: 

You can use a normal for loop backwards, like this:

for (int i = collection.Count - 1; i >= 0 ; i--) {
    var current = collection[i];
    //Do things
}

You can also use LINQ:

foreach(var current in collection.Reverse()) {
    //Do things
}

However, the normal for loop will probably be a little bit faster.

SLaks
The `for` loop may be faster, but the LINQ is certainly clearer. I would therefore prefer the LINQ version.
jball
+1 for an extension method I forgot about!
David
I don't know why I didn't realize you could traverse through a collection with brackets... so i guess its justfor (int i = collections.Count; i >= 0; i--)... Ugh I'm a moron. Thanks.
Sam F
@Sam F. No you are not! :-)
Moron
@jball: Iterating backwards in a for loop is somehow "unclear"? Really?
Ed Swangren
@Sam F: Not all collections have random access (ie. brackets), so you're not wrong in any case. :)
Kyte
Note that your first example only works if the Collection has an indexer; not all collections do. `Reverse` is the best option.
Randolpho
That username is genius. I love the fact that everyone will address you as "Hey, moron"
Pierreten
@Kyte, @Randolpho: AFAIK, the only collections that don't have indexers are the intrinsically unordered ones (eg, Dictionary.ValuesCollection), which you shoudn't be reversing in the first place.
SLaks
@Ed: In this age of iterators and LINQ, for loops seem downright antiquated.
Pierreten
@SLaks: you left out `LinkedList`, which is ordered and reversible, but is not indexible.
Randolpho
@SLaks: I may be defiling the proper use of IEnumerable, but I tend to use them even on objects that have easy linear transversal but no random access. Say, data incoming from a network stream or a sequential-access file. (That last one was for homework, mind you.)
Kyte
@SLaks: and as I go through them, there are `SortedDictionary`, `SortedSet`, and `Stack`, all of which are ordered and reversible, but not indexible. And that's just in the `System.Collections.Generic` namespace... I could search for more...
Randolpho
@Ed Swangren, you really think the loop is as clear as the LINQ? The LINQ expresses in 1 line using an english verb as the method name what it will do. The `for` loop requires 2 lines, awareness of the bounds of the list, and succeeds in saying "reverse" via `--`. The LINQ is clearly more expressive.
jball
@Randolpho: I stand corrected.
SLaks
I didn't look, but `Reverse()` is probably smart enough to use indexes if they are available. For instance, the LINQ `Count()` method is smart enough to access the `Length` or `Count` property if it exists, and to count the elements in the enumeration one-by-one only if no such property exists.
Phong
@SLaks: Reading back I realize I sound a little dickish with that; such was not my intent. I'm just trying to point out that it's best to use `Reverse` for the general case, since not every collection has an indexer.
Randolpho
+3  A: 

If you're using 3.5, looks like there is a Reverse() method in LINQ That won't iterate through in reverse order, but would reverse the entire list, then you could do your foreach.

Or you could use a simple for statement:

for(int i = list.Count -1; i >= 0; --i)
{
   x = list[i];
}
taylonr
You're asking for an `IndexOutOfBounds` error. Start at `i = count - 1`
Greg
@taylonr: "That won't iterate through in reverse order, but would reverse the entire list." This is untrue. Iterating in reverse order is *precisely* what the `Enumerable.Reverse<T>` extension method does. You may be thinking of `List<T>.Reverse`, which [confusingly has the same name](http://stackoverflow.com/questions/2828917/most-awkward-misleading-method-in-the-net-api/2829051#2829051).
Dan Tao
@Greg, good catch, updated.@Dan Tao, I was thinking of List<T>.Reverse.
taylonr
@Greg yeah I noticed that after it crashed thanks :P
Sam F
+4  A: 

You could just call Reverse() on the collection.

foreach(var item in collection.Reverse()) { ... }
48klocs
I don't believe there is a Reverse() on Collections<class> that was my first thought.
Sam F
@Sam F: It's an [extension method](http://msdn.microsoft.com/en-us/library/bb383977.aspx) on any `IEnumerable<T>` (which includes `Collection<T>`), available from .NET 3.5 onwards. See [here](http://msdn.microsoft.com/en-us/library/system.linq.enumerable_methods.aspx) for a list of all of them. If you're using .NET 3.5 or later you just need to add `using System.Linq;` to the top of your file.
Dan Tao
I suppose I should add a note - confusingly enough, Reverse() has a different meaning for IList<T> than it does for standard IEnumerable<T>.IList<T>.Reverse() returns void so in order for my snippet to work, you'd have to say collection.AsEnumerable().Reverse(). Confusing business, that.
48klocs
+2  A: 

Alternatively, if the collection's an IEnumerable and therefore without random access, use System.Linq's IEnumerable.Reverse() method and apply forearch as usual.

using System.Linq;

foreach (var c in collection.Reverse()) {
}
Kyte
Reverse is the only *viable* option for reverse iterating over a collection. Too many collections are not indexible.
Randolpho
A: 
        List<string> items = new List<string> 
        { 
            "item 1", 
            "item 2",
            "item 3", 
            "item 4", 
        };
        lines.AsEnumerable().Reverse()
                            .Do(a => Console.WriteLine(a), ex => Console.WriteLine(ex.Message), () => Console.WriteLine("Completed"))
                            .Run();           

Reactive Extension for .NET 3.5/4.0

Kthurein