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.