¿Cómo obtener una vista de lista invertida en una lista en Java?

214

Quiero tener una vista de lista invertida en una lista (de manera similar a la que List#sublistproporciona una vista de sublista en una lista). ¿Hay alguna función que proporcione esta funcionalidad?

No quiero hacer ningún tipo de copia de la lista ni modificarla.

Sin embargo, sería suficiente si pudiera obtener al menos un iterador inverso en una lista en este caso.


Además, sé cómo implementar esto yo mismo. Solo pregunto si Java ya proporciona algo como esto.

Implementación de demostración:

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

Acabo de descubrir que algunas Listimplementaciones tienen descendingIterator()lo que necesito. Aunque no existe tal implementación general para List. Lo cual es un poco extraño porque la implementación que he visto LinkedListes lo suficientemente general como para funcionar con cualquiera List.

Albert
fuente
1
¿Puedes construir la lista en el orden inverso para empezar?
Tony Ennis
Sí, lo hace - java.uitl.List.listIterator (int) download.oracle.com/javase/6/docs/api/java/util/…
TofuBeer
Si visita este enlace para encontrar la respuesta sobre cómo revertir (modificar) la lista, esta es la respuesta:Collections.reverse(list)
ZhaoGang

Respuestas:

209

Guava proporciona esto: Lists.reverse (List)

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

diferente a Collections.reverse , esto es puramente una vista ... no altera el orden de los elementos en la lista original. Además, con una lista original que es modificable, los cambios tanto en la lista original como en la vista se reflejan en la otra.

ColinD
fuente
11
El problema es que la guayaba es una biblioteca muy grande. Vea la discusión: github.com/google/guava/issues/1954 y code.google.com/p/guava-libraries/issues/detail?id=605
Filipe Brito
2
@Filipe de Lima Brito: ProGuard sigue siendo la mejor solución para el tamaño de la biblioteca, aunque es probable que podamos realizar mejoras. En cualquier caso, no creo que el tamaño de la biblioteca sea relevante de ninguna manera para esta respuesta.
ColinD
2
Sí, el tamaño de la biblioteca no es relevante para esta respuesta, ¡pero es relevante estar informado para los programadores (por lo tanto, comenté)! ¡Muchas gracias por esta gran biblioteca y por su sugerencia @ColinD!
Filipe Brito
@ColinD, sí, fue mi error. Un colega agregó colecciones de google que también tienen el mismo espacio de nombres y clase ( List) pero sin método inverso. al quitarlo, la guayaba volvió a estar disponible.
AaA 01 de
Los desarrolladores no siempre tienen control sobre lo bibliotecas que pueden utilizar, y la adición de una biblioteca totalmente nueva para algo tan simple parece un exceso - especialmente teniendo en cuenta que el problema puede ser resuelto conListIterator.previous()
Jonathan Benn
218

Use el método .clone () en su Lista. Devolverá una copia superficial, lo que significa que contendrá punteros a los mismos objetos, por lo que no tendrá que copiar la lista. Entonces solo use Colecciones.

Es decir,

Collections.reverse(list.clone());

Si está utilizando Listay no tiene acceso clone(), puede usar subList():

List<?> shallowCopy = list.subList(0, list.size());
Collections.reverse(shallowCopy);
jcalvert
fuente
21
clone()normalmente crearía una copia de la lista. De todos modos, List#clone()tampoco existe.
Albert
66
Técnicamente tiene razón, la interfaz de Lista en sí no proporciona el método clone (). Pero ArrayList, LinkedList y Vector sí.
jcalvert
2
Acabo de buscar la implementación de clone(). De hecho, hace una copia completa de la lista (solo no clona cada objeto en la lista, pero eso nunca fue de lo que estaba hablando).
Albert
21
Tenga en cuenta que Collections.reverse devuelve nulo, por lo que perderá la referencia de clonación. Primero debe asignar el clon a una variable, luego ordenarlo.
usuario12722
10
subListno copia, solo proporciona una vista de la lista subyacente, por lo tanto, invertir esta vista revertirá la lista subyacente.
Roland
80

Si he entendido bien, entonces es una línea de código. Funcionó para mí.

 Collections.reverse(yourList);
Shakeeb Ayaz
fuente
12
Esa no es una vista de lista. Eso modifica la lista.
Albert
35

No es exactamente elegante, pero si usa List.listIterator (int index) puede obtener un ListIterator bidireccional al final de la lista:

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

while (li.hasPrevious()) {
   String curr = li.previous()
}
kkress
fuente
1
Esta es la mejor respuesta, ya que (1) no requiere una biblioteca y (2) no modifica la lista original, como solicitó el OP
Jonathan Benn
12

Collections.reverse (nums) ... Realmente invierte el orden de los elementos. El siguiente código debe ser muy 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);

Salida: 15,94,83,42,61

Krishna Kumar Chourasiya
fuente
8
Simplemente estás repitiendo la respuesta que alguien más escribió hace 6 años
Jonathan Benn
1
... y no una vista. esto muta la lista.
Jason S
6

java.util.Dequetiene descendingIterator()- si tu Listes un Deque, puedes usar eso.

Bozho
fuente
Si no desea utilizar el método descndingIterator () incorporado, parece que usar un ConcurrentLinkedDeque sería lo mejor para revertir una lista muy grande. Básicamente, simplemente copie de un mazo al nuevo mazo usando la encuesta y luego ofrezca. Ordena como tener una baraja de cartas y sacar cada una de ellas en una nueva pila, en orden.
djangofan 01 de
4

Sé que esta es una publicación antigua, pero hoy estaba buscando algo como esto. Al final escribí el código yo mismo:

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

No se recomienda para listas largas, esto no está optimizado en absoluto. Es una especie de solución fácil para escenarios controlados (las Listas que manejo no tienen más de 100 elementos).

Espero que ayude a alguien.

CocheLee
fuente
2
Su código tiene un problema: puede incluir cualquier Lista, pero siempre le devolverá ArrayList (como Lista). ¿Y si necesito LinkedList? Es mejor modificar myList y devolver nulo.
Dmitry Zaytsev
2
Tenga en cuenta que esto no es realmente lo que estaba pidiendo. Estaba pidiendo algún tipo de proxy / vista, no una copia.
Albert
4

Yo uso esto:

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

}

Me gusta esto:

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

También puedes hacer esto:

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
fuente
55
Esa no es una vista de lista. Una vista es lo contrario de una copia.
Albert
¿La lista inversa de una lista vacía es nula?
ShellFish
1

También puede invertir la posición cuando solicita un objeto:

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

Para una lista de tamaño pequeño, podemos crear LinkedListy luego usar el 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
fuente
-3

Utiliza reverse(...)métodos de java.util.Collectionsclase. Pase su lista como parámetro y su lista se revertirá.

Collections.reverse(list);
Shubho Ghosh
fuente
1
Copia de una respuesta existente
Karl Richter