2010-10-18 6 views
160

Ich möchte eine umgekehrte Listenansicht auf einer Liste haben (ähnlich wie List#sublist bietet eine Unterliste Ansicht auf einer Liste). Gibt es eine Funktion, die diese Funktionalität bietet?Wie man eine Liste in Java umkehrt?

Ich möchte keine Kopie der Liste machen oder die Liste ändern.

Es wäre genug, wenn ich in diesem Fall zumindest einen umgekehrten Iterator in einer Liste bekommen könnte.


Auch ich weiß, wie ich das selbst implementieren. Ich frage nur, ob Java schon so etwas bietet.

Demo Implementierung:

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(); }     
      }; 
     } 
    }; 
} 

Ich habe gerade herausgefunden, dass einige List Implementierungen descendingIterator() haben das ist, was ich brauche. Obwohl es keine allgemeine Implementierung für List gibt. Das ist irgendwie komisch, weil die Implementierung, die ich in LinkedList gesehen habe, allgemein genug ist, mit irgendeiner List zu arbeiten.

+1

Können Sie die Liste in umgekehrter Reihenfolge erstellen? –

+0

Ja, es tut - java.uitl.List.listIterator (int) http://download.oracle.com/javase/6/docs/api/java/util/List.html#listIterator%28int%29 – TofuBeer

Antwort

151

Guava dies bietet: Lists.reverse(List)

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

Im Gegensatz zu Collections.reverse, das ist eine reine Ansicht ... es nicht die Reihenfolge der Elemente in der ursprünglichen Liste verändern. Bei einer ursprünglichen Liste, die geändert werden kann, werden Änderungen an der ursprünglichen Liste und der Ansicht in der anderen reflektiert.

+5

Das Problem ist Guava ist eine sehr große Bibliothek. Siehe die Diskussion: https://github.com/google/guava/issues/1954 und https://code.google.com/p/guava-libraries/issues/detail?id=605 –

+1

@Filipe de Lima Brito: ProGuard ist immer noch die beste Lösung für die Bibliotheksgröße, obwohl es wahrscheinlich Verbesserungen gibt, die wir machen können. Auf jeden Fall glaube ich nicht, dass die Größe der Bibliothek in irgendeiner Weise für diese Antwort relevant ist. – ColinD

+1

Ja, die Größe der Bibliothek ist für diese Antwort nicht relevant, aber relevant für die Programmierer (daher habe ich kommentiert)! Vielen Dank für diese tolle Bibliothek und für Ihren Vorschlag @ColinD! –

23

Es ist nicht genau elegant, aber wenn Sie verwenden List.listIterator (int index) Sie einen bidirektionalen ListIterator zum Ende der Liste bekommen:

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

while (li.hasPrevious()) { 
    String curr = li.previous() 
} 
4

java.util.Deque hat descendingIterator() - wenn Ihr List ist a Deque, können Sie das verwenden.

+0

Wenn Sie die integrierte Methode descendingIterator() nicht verwenden möchten, scheint es, als ob die Verwendung einer ConcurrentLinkedDeque am besten ist, um eine sehr große Liste umzukehren. Im Grunde nur kopieren von einem Deck auf das neue Deck mit Umfrage dann Angebot? Sorta, als hätte man nur ein Kartenspiel und nimmt jeden von oben in einen neuen Stapel. – djangofan

173

Verwenden Sie die .clone() -Methode für Ihre Liste. Es wird eine flache Kopie zurückgegeben, was bedeutet, dass es Zeiger auf dieselben Objekte enthält, so dass Sie die Liste nicht kopieren müssen. Dann benutze einfach die Sammlungen.

Ergo,

Collections.reverse(list.clone()); 

Wenn Sie eine List verwenden und haben keinen Zugriff auf clone() Sie subList() verwenden können:

List<?> shallowCopy = list.subList(0, list.size()); 
Collections.reverse(shallowCopy); 
+18

'clone()' würde normalerweise eine Kopie der Liste erstellen. Wie auch immer, 'List # clone()' existiert auch nicht. – Albert

+6

Sie haben technisch Recht, die List-Schnittstelle selbst bietet die clone() -Methode nicht. Aber ArrayList, LinkedList und Vector tun alles. – jcalvert

+0

Klon ist eine * flache * Kopie der Liste. Es wird nicht die Mitglieder kopieren. Aber ich denke, ich verstehe, wo Sie jetzt mit diesem Thema hinfahren, in Bezug auf eine "Ansicht", da jede strukturelle Änderung der "Ansicht" von subList() auch das Original verändert. Ich glaube nicht, dass Sie etwas tun können, was Sie wollen, ohne eine Klasse zu erstellen, wie Sie es in Ihrer Demo getan haben. " – jcalvert

4

Ich weiß, dass dies eine alte Post, aber heute war ich auf der Suche nach so etwas. Am Ende habe ich den Code selbst:

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; 
} 

Nicht lange Listen empfohlen, ist dies nicht optimiert. Es ist eine einfache Lösung für kontrollierte Szenarien (die Listen, die ich behandle, haben nicht mehr als 100 Elemente).

Ich hoffe, es hilft jemandem.

+1

Ihr Code hat ein Problem - Sie können eine beliebige Liste hinzufügen, aber Sie erhalten immer ArrayList (als Liste) zurück. Und was ist, wenn ich LinkedList brauche? Es ist besser, myList zu ändern und void zurückzugeben. –

+1

Beachten Sie, dass dies nicht wirklich das ist, wonach ich gefragt habe. Ich habe nach einer Art Proxy/View gefragt, nicht nach einer Kopie. – Albert

1

Sie können dies auch tun:

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; 
} 
+5

Das ist keine Listenansicht. Eine Ansicht ist das Gegenteil einer Kopie. – Albert

+0

Die umgekehrte Liste einer leeren Liste ist null ?? – ShellFish

68

Wenn ich richtig verstanden haben, dann ist es eine Zeile Code .Es für mich gearbeitet.

Collections.reverse(yourList); 
+6

Das ist keine Listenansicht. Das ändert die Liste. – Albert

+1

oops Ich habe falsch verstanden .. –

+0

Diese Antwort kam gerade: geringe Qualität: Überprüfung. – Jayan

2

ich verwenden:

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(); 
    } 

} 

wie folgt aus:

ReversedView.of(backingList) // is a fully-fledged generic (but read-only) list 
6

Collections.reverse (nums) ... Es umkehren tatsächlich die Reihenfolge der Elemente. Im Folgenden Code sollte sehr geschätzt werden -

List<Integer> nums = new ArrayList<Integer>(); 
nums.add(61); 
nums.add(42); 
nums.add(83); 
nums.add(94); 
nums.add(15); 

Collections.sort(nums); 

Collections.reverse(nums); 

System.out.println(nums); 
0

Sie können auch die Position invertieren, wenn Sie ein Objekt anfordern:

Object obj = list.get(list.size() - 1 - position); 
0

für kleine Liste, die wir LinkedList und die Verwendung von absteigend Iterator machen können dann erstellen wie:

List<String> stringList = new ArrayList<>(Arrays.asList("One", "Two", "Three")); 
stringList.stream().collect(Collectors.toCollection(LinkedList::new)) 
     .descendingIterator(). 
     forEachRemaining(System.out::println); // Four, Three, Two, One 
System.out.println(stringList); // One, Two, Three, Four