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.


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.


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

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

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

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


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.


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.


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

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

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

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

-3

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

Collections.reverse(list);

1
Cópia de uma resposta existente
Karl Richter
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.