Como obter uma exibição de lista invertida em uma lista em Java?

214

Desejo ter uma exibição de lista invertida em uma lista (de maneira semelhante ao que List#sublistfornece uma exibição de sub-lista em uma lista). Existe alguma função que fornece essa funcionalidade?

Não quero fazer nenhum tipo de cópia da lista nem modificá-la.

Seria o suficiente se eu pudesse obter pelo menos um iterador reverso em uma lista nesse caso.


Além disso, eu sei como implementar isso sozinho. Só estou perguntando se o Java já fornece algo assim.

Implementação de demonstração:

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

Acabei de descobrir que algumas Listimplementações têm o descendingIterator()que eu preciso. Embora não exista essa implementação geral para List. O que é meio estranho, porque a implementação que eu vi LinkedListé geral o suficiente para funcionar com qualquer List.

Albert
fonte
1
Você pode criar a lista na ordem inversa para começar?
Tony Ennis
Sim, ele funciona - java.uitl.List.listIterator (int) download.oracle.com/javase/6/docs/api/java/util/…
TofuBeer
Se você visitar este link para encontrar a resposta como reverter (modificar) a lista, esta é a resposta:Collections.reverse(list)
ZhaoGang

Respostas:

209

A Goiaba fornece o seguinte: Lists.reverse (Lista)

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

Ao contrário Collections.reverse, essa é uma visão puramente ... não altera a ordem dos elementos na lista original. Além disso, com uma lista original modificável, as alterações na lista original e na exibição são refletidas na outra.

ColinD
fonte
11
O problema é que o Goiaba é uma biblioteca muito grande. Veja a discussão: github.com/google/guava/issues/1954 e code.google.com/p/guava-libraries/issues/detail?id=605
Filipe Brito
2
@Filipe de Lima Brito: O ProGuard ainda é a melhor solução para o tamanho da biblioteca, embora haja melhorias prováveis ​​que podemos fazer. De qualquer forma, não acho que o tamanho da biblioteca seja relevante para essa resposta.
ColinD 15/07
2
Sim, o tamanho da biblioteca não é relevante para esta resposta, mas é relevante para ser informado pelos programadores (portanto, comentei)! Muito obrigado por esta ótima biblioteca e por sua sugestão @ColinD!
Filipe Brito
@ CololinD, sim, foi um erro meu. Um colega adicionou coleções de google que também têm o mesmo namespace e classe ( List), mas sem método reverso. removê-lo tornou a goiaba disponível novamente.
AaA
Desenvolvedores nem sempre têm controle sobre quais bibliotecas podem usar, e adicionando uma nova biblioteca inteira para algo tão simples parece um exagero - especialmente tendo em conta que o problema pode ser resolvido comListIterator.previous()
Jonathan Benn
218

Use o método .clone () na sua lista. Ele retornará uma cópia superficial, o que significa que conterá ponteiros para os mesmos objetos, para que você não precise copiar a lista. Depois, basta usar Coleções.

Ergo,

Collections.reverse(list.clone());

Se você estiver usando um Liste não tiver acesso, clone()poderá usar subList():

List<?> shallowCopy = list.subList(0, list.size());
Collections.reverse(shallowCopy);
jcalvert
fonte
21
clone()normalmente criaria uma cópia da lista. Enfim, List#clone()também não existe.
Albert
6
Você está tecnicamente certo, a interface List em si não fornece o método clone (). Mas ArrayList, LinkedList e Vector todos fazem.
jcalvert
2
Eu apenas procurei a implementação do clone(). Na verdade, ele faz uma cópia completa da lista (apenas não clona cada objeto da lista, mas nunca foi sobre isso que eu estava falando).
Albert
21
Observe que Collections.reverse retorna nulo, para que você perca a referência do clone. Você precisa atribuir o clone a uma variável primeiro e depois classificá-lo.
usar o seguinte comando
10
subListnão copia, apenas fornece uma exibição na lista subjacente; portanto, reverter essa exibição reverterá a lista subjacente.
Roland
80

Se eu entendi correto, então é uma linha de código. Funcionou para mim.

 Collections.reverse(yourList);
Shakeeb Ayaz
fonte
12
Essa não é uma exibição de lista. Isso modifica a lista.
Albert
35

Não é exatamente elegante, mas se você usar List.listIterator (int index), poderá obter um ListIterator bidirecional no final da lista:

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

while (li.hasPrevious()) {
   String curr = li.previous()
}
kkress
fonte
1
Esta é a melhor resposta, pois (1) ela não requer uma biblioteca e (2) não modifica a lista original, conforme solicitado pelo OP #
Jonathan Benn
12

Collections.reverse (nums) ... Na verdade, inverte a ordem dos elementos. O código abaixo deve ser muito apreciado -

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

Saída: 15,94,83,42,61

Krishna Kumar Chourasiya
fonte
8
Você está apenas repetindo a resposta que outra pessoa escreveu há 6 anos
Jonathan Benn
1
... e não uma vista. isso muda a lista.
Jason S
6

java.util.Dequehas descendingIterator()- se você Listé um Deque, você pode usá-lo.

Bozho
fonte
Se você não quiser usar o método descndingIterator () interno, parece que usar um ConcurrentLinkedDeque seria o melhor para reverter uma lista muito grande. Basicamente, basta copiar de um deck para o novo deck usando a enquete e oferecer? É como ter apenas um baralho de cartas e levar cada uma do topo para uma nova pilha, em ordem.
djangofan
4

Eu sei que este é um post antigo, mas hoje eu estava procurando por algo assim. No final, eu mesmo escrevi o código:

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

Não recomendado para listas longas, isso não é otimizado. É uma solução fácil para cenários controlados (as Listas que mantenho não têm mais que 100 elementos).

Espero que ajude alguém.

CocheLee
fonte
2
Seu código tem um problema - você pode colocar qualquer lista nele, mas sempre retornará você ArrayList (como Lista). E se eu precisar do LinkedList? É melhor modificar myList e retornar nulo.
Dmitry Zaytsev
2
Note que isso não é realmente o que eu estava pedindo. Eu estava pedindo algum tipo de proxy / view, não uma cópia.
Albert
4

Eu uso isso:

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

}

como isso:

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

Você também pode fazer isso:

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
fonte
5
Essa não é uma exibição de lista. Uma visão é o oposto de uma cópia.
Albert
A lista reversa de uma lista vazia é nula ??
ShellFish
1

Você também pode inverter a posição ao solicitar um objeto:

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

Para lista de tamanho pequeno, podemos criar LinkedListe usar o iterador descendente como:

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

Use reverse(...)métodos de java.util.Collectionsclasse. Passe sua lista como parâmetro e sua lista será revertida.

Collections.reverse(list);
Shubho Ghosh
fonte
1
Cópia de uma resposta existente
Karl Richter