245

I want to have a reversed list view on a list (in a similar way than List#sublist provides a sublist view on a list). Is there some function which provides this functionality?

I don't want to make any sort of copy of the list nor modify the list.

It would be enough if I could get at least a reverse iterator on a list in this case though.


Also, I know how to implement this myself. I'm just asking if Java already provides something like this.

Demo implementation:

static <T> Iterable<T> iterableReverseList(final List<T> l) {
    return new Iterable<T>() {
        public Iterator<T> iterator() {
            return new Iterator<T>() {
                ListIterator<T> listIter = l.listIterator(l.size());                    
                public boolean hasNext() { return listIter.hasPrevious(); }
                public T next() { return listIter.previous(); }
                public void remove() { listIter.remove(); }                 
            };
        }
    };
}

I just have found out that some List implementations have descendingIterator() which is what I need. Though there is no general such implementation for List. Which is kind of strange because the implementation I have seen in LinkedList is general enough to work with any List.

ZhaoGang
  • 4,491
  • 1
  • 27
  • 39
Albert
  • 65,406
  • 61
  • 242
  • 386

12 Answers12

240

Use the .clone() method on your List. It will return a shallow copy, meaning that it will contain pointers to the same objects, so you won't have to copy the list. Then just use Collections.

Ergo,

Collections.reverse(list.clone());

If you are using a List and don't have access to clone() you can use subList():

List<?> shallowCopy = list.subList(0, list.size());
Collections.reverse(shallowCopy);
RustyTheBoyRobot
  • 5,891
  • 4
  • 36
  • 55
jcalvert
  • 3,628
  • 2
  • 19
  • 13
  • 22
    `clone()` normally would create a copy of the list. Anyway, `List#clone()` also does not exist. – Albert Oct 18 '10 at 20:31
  • 6
    You are technically right, the List interface itself doesn't provide the clone() method. But ArrayList, LinkedList and Vector all do. – jcalvert Oct 18 '10 at 21:15
  • Clone is a *shallow* copy of the list. It will not copy the members. But I think I understand where you're going with this now, in reference to a "view", as any structural change to the 'view' from subList() alters the original as well. I don't think you have any way to do what you want without creating a class as you did in your demo. – jcalvert Oct 18 '10 at 21:26
  • 2
    I just looked up the implementation of `clone()`. It indeed does a full copy of the list (it only does not clone each single object in the list but that was never what I was talking about). – Albert Oct 18 '10 at 23:06
  • 26
    Note that Collections.reverse returns void, so you would lose the clone reference. You need to assign the clone to a variable first, then sort it. – user12722 Apr 16 '15 at 03:25
  • 15
    `subList` doesn't copy, it just provides a view on the underlying list, therefore reversing this view will reverse the underlying list. – Roland Jul 05 '17 at 05:19
  • ArrayList.clone returns Object which is not accepted by Collections.reverse() – Florent Nov 18 '21 at 22:54
231

Guava provides this: Lists.reverse(List)

List<String> letters = ImmutableList.of("a", "b", "c");
List<String> reverseView = Lists.reverse(letters); 
System.out.println(reverseView); // [c, b, a]

Unlike Collections.reverse, this is purely a view... it doesn't alter the ordering of elements in the original list. Additionally, with an original list that is modifiable, changes to both the original list and the view are reflected in the other.

ColinD
  • 108,630
  • 30
  • 201
  • 202
  • 19
    The problem is that Guava is a very large library. See the discussion: https://github.com/google/guava/issues/1954 and https://code.google.com/p/guava-libraries/issues/detail?id=605 – Filipe Brito Jul 15 '15 at 18:04
  • 3
    @Filipe de Lima Brito: ProGuard is still the best solution for library size, though there are likely improvements we can make. In any case, I don't think library size is relevant in any way to this answer. – ColinD Jul 15 '15 at 18:59
  • 3
    Yes, the library size isn’t relevant to this answer, but is relevant to be informed for the programmers (therefore, I commented)! Thank you very much for this great library and for your suggestion @ColinD! – Filipe Brito Jul 15 '15 at 19:42
  • @ColinD, yup, it was my mistake. A colleague added google-collections which also have same namespace and class (`List`) but without reverse method. removing it made guava available again. – AaA Jul 01 '16 at 02:44
  • Developers don't always have control over what libraries they can use, and adding a whole new library for something so simple seems like overkill--especially given that the problem can be solved with `ListIterator.previous()` – Jonathan Benn Oct 17 '18 at 17:37
  • @JonathanBenn the problem is that the problem is not so simple. You have so many implementations of `List` that reversing it appropriately entirely depends on the context (do you use a List for its index, do you use it for the ordered property, etc.) This answer is the best at mixing all those. – Olivier Grégoire Apr 07 '20 at 13:30
  • Agree, the response of jcalvert is way better, because it uses the standard library. Guava just cause problems with other frameworks. You can say "it pollutes" your code. – Brain Jun 05 '20 at 08:16
81

If i have understood correct then it is one line of code .It worked for me .

 Collections.reverse(yourList);
Shakeeb Ayaz
  • 6,200
  • 6
  • 45
  • 64
43

Its not exactly elegant, but if you use List.listIterator(int index) you can get a bi-directional ListIterator to the end of the list:

//Assume List<String> foo;
ListIterator li = foo.listIterator(foo.size());

while (li.hasPrevious()) {
   String curr = li.previous();
}
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
kkress
  • 777
  • 5
  • 6
  • 1
    This is the best answer, since (1) it does not require a library, and (2) it does not modify the original list, as the OP requested – Jonathan Benn Oct 17 '18 at 17:30
10

I use this:

public class ReversedView<E> extends AbstractList<E>{

    public static <E> List<E> of(List<E> list) {
        return new ReversedView<>(list);
    }

    private final List<E> backingList;

    private ReversedView(List<E> backingList){
        this.backingList = backingList;
    }

    @Override
    public E get(int i) {
        return backingList.get(backingList.size()-i-1);
    }

    @Override
    public int size() {
        return backingList.size();
    }

}

like this:

ReversedView.of(backingList) // is a fully-fledged generic (but read-only) list
Museful
  • 6,711
  • 5
  • 42
  • 68
8

java.util.Deque has descendingIterator() - if your List is a Deque, you can use that.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • If you didn't want to use built-in descndingIterator() method, it seems like using a ConcurrentLinkedDeque would be the best to reverse a very large list? Basically just copy from one deck to the new deck using poll then offer ? Sorta like just having a deck of cards and taking each off the top into a new pile, in order. – djangofan Jul 01 '17 at 18:54
6

Collections.reverse(nums) ... It actually reverse the order of the elements. Below code should be much appreciated -

List<Integer> nums = new ArrayList<Integer>();
nums.add(61);
nums.add(42);
nums.add(83);
nums.add(94);
nums.add(15);
//Tosort the collections uncomment the below line
//Collections.sort(nums); 

Collections.reverse(nums);

System.out.println(nums);

Output: 15,94,83,42,61

Naveed Ahmad
  • 6,627
  • 2
  • 58
  • 83
Krishna Kumar Chourasiya
  • 2,030
  • 3
  • 20
  • 23
3

I know this is an old post but today I was looking for something like this. In the end I wrote the code myself:

private List reverseList(List myList) {
    List invertedList = new ArrayList();
    for (int i = myList.size() - 1; i >= 0; i--) {
        invertedList.add(myList.get(i));
    }
    return invertedList;
}

Not recommended for long Lists, this is not optimized at all. It's kind of an easy solution for controlled scenarios (the Lists I handle have no more than 100 elements).

Hope it helps somebody.

Sergey Glotov
  • 20,200
  • 11
  • 84
  • 98
CocheLee
  • 121
  • 8
  • 2
    Your code have a one problem - you can put any List to it, but it'll always return you ArrayList (as List). And what if I need LinkedList? It's better to modify myList, and return void. – Dmitry Zaytsev Apr 27 '12 at 12:45
  • 2
    Note that this is not really what I was asking for. I was asking for some sort of proxy/view, not a copy. – Albert Apr 27 '12 at 14:26
2

Since Java 21 there is a new interface SequencedCollection (which is a superinteface for List). It has the method reversed() which provides a reverse-ordered view of a collection:

jshell> List.of(1, 2, 3, 4, 5).reversed()
$1 ==> [5, 4, 3, 2, 1]
ZhekaKozlov
  • 36,558
  • 20
  • 126
  • 155
1

You can also invert the position when you request an object:

Object obj = list.get(list.size() - 1 - position);
fede1608
  • 2,808
  • 1
  • 16
  • 17
1

For small sized list we can create LinkedList and then can make use of descending iterator as:

List<String> stringList = new ArrayList<>(Arrays.asList("One", "Two", "Three"));
stringList.stream().collect(Collectors.toCollection(LinkedList::new))
         .descendingIterator().
         forEachRemaining(System.out::println); // Three, Two, One
System.out.println(stringList); // One, Two, Three
akhil_mittal
  • 23,309
  • 7
  • 96
  • 95
-1

You can also do this:

static ArrayList<String> reverseReturn(ArrayList<String> alist)
{
   if(alist==null || alist.isEmpty())
   { 
       return null;
   }

   ArrayList<String> rlist = new ArrayList<>(alist);

   Collections.reverse(rlist);
   return rlist;
}
akjoshi
  • 15,374
  • 13
  • 103
  • 121
jhdrosos
  • 23
  • 3