Wie erhalte ich eine umgekehrte Listenansicht für eine Liste in Java?

214

Ich möchte eine umgekehrte List#sublistListenansicht für eine Liste haben (ähnlich wie bei einer Unterlistenansicht für eine Liste). Gibt es eine Funktion, die diese Funktionalität bietet?

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

In diesem Fall wäre es jedoch ausreichend, wenn ich mindestens einen Reverse-Iterator auf eine Liste setzen könnte.


Außerdem weiß ich, wie ich das selbst umsetzen kann. Ich frage nur, ob Java so etwas bereits 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 ListImplementierungen genau das haben, descendingIterator()was ich brauche. Obwohl es keine allgemeine solche Implementierung für gibt List. Was irgendwie seltsam ist, weil die Implementierung, die ich gesehen habe, LinkedListallgemein genug ist, um mit jeder zu arbeiten List.

Albert
quelle
1
Können Sie die Liste zunächst in umgekehrter Reihenfolge erstellen?
Tony Ennis
Ja, das tut es - java.uitl.List.listIterator (int) download.oracle.com/javase/6/docs/api/java/util/…
TofuBeer
Wenn Sie diesen Link besuchen, um die Antwort zu finden, wie Sie die Liste umkehren (ändern), ist dies die Antwort:Collections.reverse(list)
ZhaoGang

Antworten:

209

Guave bietet dies: Lists.reverse (Liste)

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

Im Gegensatz Collections.reversedazu ist dies nur eine Ansicht ... es ändert nichts an der Reihenfolge der Elemente in der ursprünglichen Liste. Bei einer ursprünglichen Liste, die geändert werden kann, werden Änderungen sowohl an der ursprünglichen Liste als auch an der Ansicht in der anderen wiedergegeben.

ColinD
quelle
11
Das Problem ist, dass Guava eine sehr große Bibliothek ist. Siehe die Diskussion: github.com/google/guava/issues/1954 und code.google.com/p/guava-libraries/issues/detail?id=605
Filipe Brito
2
@Filipe de Lima Brito: ProGuard ist immer noch die beste Lösung für die Bibliotheksgröße, obwohl wir wahrscheinlich Verbesserungen vornehmen können. Auf jeden Fall denke ich nicht, dass die Bibliotheksgröße in irgendeiner Weise für diese Antwort relevant ist.
ColinD
2
Ja, die Bibliotheksgröße ist für diese Antwort nicht relevant, aber relevant, um für die Programmierer informiert zu werden (daher habe ich kommentiert)! Vielen Dank für diese großartige Bibliothek und für Ihren Vorschlag @ColinD!
Filipe Brito
@ColinD, yup, es war mein Fehler. Ein Kollege fügte Google-Sammlungen hinzu, die ebenfalls denselben Namespace und dieselbe Klasse ( List) haben, jedoch ohne umgekehrte Methode. Durch das Entfernen wurde die Guave wieder verfügbar.
AaA
Entwickler haben nicht immer die Kontrolle über welche Bibliotheken sie verwenden können, und das Hinzufügen eine ganz neue Bibliothek für etwas so einfach wie übertrieben scheint - vor allem in Anbetracht , dass das Problem mit gelöst werden kannListIterator.previous()
Jonathan Benn
218

Verwenden Sie die Methode .clone () in Ihrer Liste. Es wird eine flache Kopie zurückgegeben, was bedeutet, dass es Zeiger auf dieselben Objekte enthält, sodass Sie die Liste nicht kopieren müssen. Dann verwenden Sie einfach Sammlungen.

Ergo,

Collections.reverse(list.clone());

Wenn Sie ein verwenden Listund keinen Zugriff darauf haben clone(), können Sie Folgendes verwenden subList():

List<?> shallowCopy = list.subList(0, list.size());
Collections.reverse(shallowCopy);
jcalvert
quelle
21
clone()Normalerweise würde eine Kopie der Liste erstellt. Sowieso existiert List#clone()auch nicht.
Albert
6
Sie haben technisch Recht, die List-Schnittstelle selbst bietet nicht die clone () -Methode. ArrayList, LinkedList und Vector tun dies jedoch alle.
Jcalvert
2
Ich habe gerade die Implementierung von nachgeschlagen clone(). Es wird tatsächlich eine vollständige Kopie der Liste erstellt (es wird nur nicht jedes einzelne Objekt in der Liste geklont, aber darüber habe ich nie gesprochen).
Albert
21
Beachten Sie, dass Collections.reverse void zurückgibt, sodass Sie die Klonreferenz verlieren würden. Sie müssen den Klon zuerst einer Variablen zuweisen und dann sortieren.
user12722
10
subListwird nicht kopiert, sondern bietet nur eine Ansicht der zugrunde liegenden Liste. Wenn Sie diese Ansicht umkehren, wird die zugrunde liegende Liste umgekehrt.
Roland
80

Wenn ich richtig verstanden habe, dann ist es eine Codezeile. Es hat bei mir funktioniert.

 Collections.reverse(yourList);
Shakeeb Ayaz
quelle
12
Das ist keine Listenansicht. Das ändert die Liste.
Albert
35

Es ist nicht gerade elegant, aber wenn Sie List.listIterator (int index) verwenden, können Sie einen bidirektionalen ListIterator an das Ende der Liste bringen:

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

while (li.hasPrevious()) {
   String curr = li.previous()
}
kkress
quelle
1
Dies ist die beste Antwort, da (1) keine Bibliothek erforderlich ist und (2) die ursprüngliche Liste nicht geändert wird, wie vom OP angefordert
Jonathan Benn,
12

Collections.reverse (nums) ... Es kehrt tatsächlich die Reihenfolge der Elemente um. Der folgende 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);
//Tosort the collections uncomment the below line
//Collections.sort(nums); 

Collections.reverse(nums);

System.out.println(nums);

Ausgabe: 15,94,83,42,61

Krishna Kumar Chourasiya
quelle
8
Sie wiederholen nur die Antwort, die jemand anderes vor 6 Jahren geschrieben hat
Jonathan Benn
1
... und keine Aussicht. Dies mutiert die Liste.
Jason S
6

java.util.Dequehat descendingIterator()- wenn du Listein Dequebist, kannst du das benutzen.

Bozho
quelle
Wenn Sie die integrierte descndingIterator () -Methode nicht verwenden möchten, ist die Verwendung einer ConcurrentLinkedDeque anscheinend die beste Methode, um eine sehr große Liste umzukehren. Grundsätzlich einfach mit Umfrage von einem Deck auf das neue Deck kopieren und dann anbieten? Sorta mag es, nur ein Kartenspiel zu haben und jedes von oben auf einen neuen Stapel zu legen.
Djangofan
4

Ich weiß, dass dies ein alter Beitrag ist, aber heute habe ich nach so etwas gesucht. Am Ende habe ich den Code selbst geschrieben:

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 empfohlen für lange Listen, dies ist überhaupt nicht optimiert. Es ist eine einfache Lösung für kontrollierte Szenarien (die von mir behandelten Listen enthalten nicht mehr als 100 Elemente).

Hoffe es hilft jemandem.

CocheLee
quelle
2
Ihr Code hat ein Problem: Sie können eine beliebige Liste hinzufügen, aber es wird immer ArrayList (als Liste) zurückgegeben. Und wenn ich LinkedList brauche? Es ist besser, myList zu ändern und void zurückzugeben.
Dmitry Zaytsev
2
Beachten Sie, dass dies nicht wirklich das ist, wonach ich gefragt habe. Ich habe nach einer Art Proxy / Ansicht gefragt, nicht nach einer Kopie.
Albert
4

Ich benutze das:

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

}

so was:

ReversedView.of(backingList) // is a fully-fledged generic (but read-only) list
Museful
quelle
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;
}
jhdrosos
quelle
5
Das ist keine Listenansicht. Eine Ansicht ist das Gegenteil einer Kopie.
Albert
Die umgekehrte Liste einer leeren Liste ist null?
ShellFish
1

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

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

Für kleine Listen können wir einen LinkedListabsteigenden Iterator erstellen und dann verwenden als:

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
quelle
-3

Verwenden Sie reverse(...)Methoden der java.util.CollectionsKlasse. Übergeben Sie Ihre Liste als Parameter und Ihre Liste wird umgekehrt.

Collections.reverse(list);
Shubho Ghosh
quelle
1
Kopie einer vorhandenen Antwort
Karl Richter