Come ottenere una vista elenco invertita su un elenco in Java?


214

Voglio avere una vista elenco invertita su un elenco (in modo simile a quello che List#sublistfornisce una vista elenco secondario su un elenco). C'è qualche funzione che fornisce questa funzionalità?

Non voglio fare alcun tipo di copia dell'elenco né modificare l'elenco.

Basterebbe se, in questo caso, potessi ottenere almeno un iteratore inverso in un elenco.


Inoltre, so come implementarlo da solo. Sto solo chiedendo se Java fornisce già qualcosa del genere.

Implementazione demo:

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

Ho appena scoperto che alcune Listimplementazioni hanno descendingIterator()ciò di cui ho bisogno. Sebbene non ci sia una tale implementazione generale per List. Il che è strano perché l'implementazione che ho visto LinkedListè abbastanza generale da funzionare con qualsiasi List.


1
Puoi costruire l'elenco in ordine inverso per cominciare?
Tony Ennis,

Sì sì - java.uitl.List.listIterator (int) download.oracle.com/javase/6/docs/api/java/util/…
TofuBeer,

Se visiti questo link per trovare la risposta su come invertire (modificare) l'elenco, questa è la risposta:Collections.reverse(list)
ZhaoGang

Risposte:


210

Guava fornisce questo: Lists.reverse (Elenco)

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

A differenza Collections.reverse, questa è puramente una vista ... non altera l'ordinamento degli elementi nell'elenco originale. Inoltre, con un elenco originale modificabile, le modifiche all'elenco originale e alla vista si riflettono nell'altro.


11
Il problema è che Guava è una libreria molto grande. Vedi la discussione: github.com/google/guava/issues/1954 e code.google.com/p/guava-libraries/issues/detail?id=605
Filipe Brito,

2
@Filipe de Lima Brito: ProGuard è ancora la soluzione migliore per le dimensioni della libreria, anche se ci sono probabilmente miglioramenti che possiamo apportare. In ogni caso, non credo che la dimensione della biblioteca sia rilevante in alcun modo per questa risposta.
ColinD,

2
Sì, la dimensione della libreria non è rilevante per questa risposta, ma è importante essere informati per i programmatori (quindi, ho commentato)! Grazie mille per questa fantastica biblioteca e per il tuo suggerimento @ColinD!
Filipe Brito,

@ColinD, sì, è stato un mio errore. Un collega ha aggiunto google-collection che hanno anche lo stesso spazio dei nomi e classe ( List) ma senza metodo inverso. rimuoverlo ha reso nuovamente disponibile la guava.
AaA

Gli sviluppatori non hanno sempre il controllo su quali librerie possono usare e l'aggiunta di una libreria completamente nuova per qualcosa di così semplice sembra eccessiva - soprattutto se si può risolvere il problemaListIterator.previous()
Jonathan Benn,

218

Usa il metodo .clone () sul tuo Elenco. Restituirà una copia superficiale, il che significa che conterrà puntatori agli stessi oggetti, quindi non dovrai copiare l'elenco. Quindi usa solo le raccolte.

Quindi,

Collections.reverse(list.clone());

Se stai usando un Liste non hai accesso a clone()puoi usare subList():

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

21
clone()normalmente creerebbe una copia dell'elenco. Comunque, List#clone()anche non esiste.
Albert,

6
Hai tecnicamente ragione, l'interfaccia List stessa non fornisce il metodo clone (). Ma ArrayList, LinkedList e Vector lo fanno tutti.
jcalvert,

2
Ho appena cercato l'implementazione di clone(). Effettivamente fa una copia completa dell'elenco (non solo clona ogni singolo oggetto nell'elenco ma non è mai stato quello di cui parlavo).
Albert,

21
Si noti che Collections.reverse restituisce null, quindi si perderebbe il riferimento al clone. Devi prima assegnare il clone a una variabile, quindi ordinarlo.
user12722

10
subListnon viene copiato, fornisce solo una vista sull'elenco sottostante, quindi invertendo questa vista si inverte l'elenco sottostante.
Roland,

80

Se ho capito bene, allora è una riga di codice. Ha funzionato per me.

 Collections.reverse(yourList);

12
Questa non è una vista elenco. Questo modifica l'elenco.
Albert

35

Non è esattamente elegante, ma se si utilizza List.listIterator (indice int) è possibile ottenere un ListIterator bidirezionale alla fine dell'elenco:

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

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

1
Questa è la risposta migliore, poiché (1) non richiede una libreria e (2) non modifica l'elenco originale, come richiesto dall'OP
Jonathan Benn,

12

Collections.reverse (nums) ... In realtà inverte l'ordine degli elementi. Il codice seguente dovrebbe essere molto apprezzato -

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

Uscita: 15,94,83,42,61


8
Stai solo ripetendo la risposta che qualcun altro ha scritto 6 anni fa
Jonathan Benn,

1
... e non una vista. questo muta la lista.
Jason S,

6

java.util.Dequeha descendingIterator()- se il tuo Listè un Deque, puoi usarlo.


Se non volessi usare il metodo descndingIterator () incorporato, sembra che usare un ConcurrentLinkedDeque sarebbe il migliore per invertire un elenco molto grande? Fondamentalmente basta copiare da un mazzo al nuovo mazzo usando il sondaggio e poi offrire? A Sorta piace avere solo un mazzo di carte e prendere ciascuna in cima a una nuova pila, in ordine.
Djangofan,

4

So che questo è un vecchio post, ma oggi stavo cercando qualcosa di simile. Alla fine ho scritto il codice da solo:

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

Non consigliato per elenchi lunghi, questo non è affatto ottimizzato. È una soluzione semplice per scenari controllati (gli elenchi che gestisco non hanno più di 100 elementi).

Spero che aiuti qualcuno.


2
Il tuo codice ha un problema: puoi inserire qualsiasi Elenco, ma ti restituirà sempre ArrayList (come Elenco). E se avessi bisogno di LinkedList? È meglio modificare myList e restituire void.
Dmitry Zaytsev,

2
Nota che questo non è proprio quello che stavo chiedendo. Stavo chiedendo una sorta di proxy / vista, non una copia.
Albert,

4

Io lo uso questo:

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

}

come questo:

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

1

Puoi anche fare questo:

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
Questa non è una vista elenco. Una vista è l'opposto di una copia.
Albert

L'elenco inverso di un elenco vuoto è null ??
ShellFish,

1

Puoi anche invertire la posizione quando richiedi un oggetto:

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

1

Per un elenco di piccole dimensioni possiamo creare LinkedListe quindi utilizzare l'iteratore discendente come:

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

-3

Usa reverse(...)metodi di java.util.Collectionsclasse. Passa la tua lista come parametro e la tua lista verrà invertita.

Collections.reverse(list);

1
Copia di una risposta esistente
Karl Richter,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.