views:

2911

answers:

7

I need to run through a List in reverse order using Java.

So where this does it forwards:

for(String string: stringList){
//...do something
}

Is there some way to iterate the stringList in reverse order using the for each syntax?

For clarity: I know how to iterate a list in reverse order but would like to know (for curiosity's sake ) how to do it in the for each style.

+4  A: 

AFAIK there isn't a standard "reverse_iterator" sort of thing in the standard library that supports the for-each syntax which is already a syntactic sugar they brought late into the language.

You could do something like for(Item element: myList.clone().reverse()) and pay the associated price.

This also seems fairly consistent with the apparent phenomenon of not giving you convenient ways to do expensive operations - since a list, by definition, could have O(N) random access complexity (you could implement the interface with a single-link), reverse iteration could end up being O(N^2). Of course, if you have an ArrayList, you don't pay that price.

Uri
You can run a ListIterator backwards, which can be wrapped up within an Iterator.
Tom Hawtin - tackline
@Tom: Good point. However, with the iterator you are still doing the annoying old-style for loops, and you may still pay the cost to get to the last element to begin with... I added the qualifier in my answer, though, thanks.
Uri
Deque has a reverse iterator.
Michael Munsey
+1  A: 

Not without writing some custom code which will give you an enumerator which will reverse the elements for you.

You should be able to do it in Java by creating a custom implementation of Iterable which will return the elements in reverse order.

Then, you would instantiate the wrapper (or call the method, what-have-you) which would return the Iterable implementation which reverses the element in the for each loop.

casperOne
+1  A: 

You can use the Collections class http://java.sun.com/j2se/1.4.2/docs/api/java/util/Collections.html to reverse the list then loop.

+1  A: 

You'd need to reverse your collection if you want to use the for each syntax out of the box and go in reverse order.

Owen
+16  A: 

For a list, you could use the Google Collections Library:

for (String item : Iterables.reverse(stringList))
{
    // ...
}

Note that this doesn't reverse the whole collection, or do anything like it - it just iterates in the reverse order. This is more efficient than reversing the collection first.

To reverse an arbitrary iterable, you'd have to read it all and then "replay" it backwards.

(If you're not already using it, I'd thoroughly recommend you have a look at the GCL. It's great stuff.)

Jon Skeet
Our codebase makes heavy use of the generified version of Commons Collections released by larvalabs (http://larvalabs.com/collections/). Looking through the SVN repo for Apache Commons, it's clear that most of the work in releasing a java 5 version of Commons Collections is done, they just haven't released it yet.
skaffman
I like it. If it weren't so useful, I'd call that a plug.
geowa4
I wonder why Jakarta never bothered to update Apache Commons.
Uri
They have updated it, that's what I'm saying. They just haven't released it.
skaffman
+7  A: 

The Collections.reverse method actually returns a new list with the elements of the original list copied into it in reverse order, so this has O(n) performance w.r.t. the size of the original list.

As a more efficient solution, you could write a decorator that presents a reversed view of a List as an Iterable. The iterator returned by your decorator would use the ListIterator of the decorated list to walk over the elements in reverse order.

For example:

public class Reversed<T> implements Iterable<T> {
    private final List<T> original;

    public Reversed(List<T> original) {
        this.original = original;
    }

    public Iterator<T> iterator() {
        final ListIterator<T> i = original.listIterator(original.size());

        return new Iterator<T>() {
            public boolean hasNext() { return i.hasPrevious(); }
            public T next() { return i.previous(); }
            public void remove() { i.remove(); }
        };
    }

    public static Reversed<T> reversed(List<T> original) {
        return new Reversed<T>(original);
    }
}

And you would use it like:

import static Reversed.reversed;

...

List<String> someStrings = getSomeStrings();
for (String s : reversed(someStrings)) {
    doSomethingWith(s);
}
Nat
That's basically what Google's Iterables.reverse does, yes :)
Jon Skeet
I know there is a 'rule' that we have to accept Jon's answer :) but.. I want to accept this one (even though they are essentially the same) because it does not require me to include another 3rd party library (even though some could argue that that reason breaks one of the prime advantages of OO - reusability).
Ron Tuffin
Small error: In public void remove(), there should not be a return statement, it should be just: i.remove();
Jesper
Thanks. I've corrected it.
Nat
+1  A: 

this will mess with the original list and also needs to be called outside of the loop. Also you don't want to perform a reverse every time you loop - would that be true if one of the Iterables.reverse ideas was applied?

Collections.reverse(stringList);

for(String string: stringList){ //...do something }

Phill

Phillip Gibb