2010-10-18 103 views
160

Quiero tener una vista de lista invertida en una lista (de manera similar que List#sublist proporciona una vista de sublista en una lista). ¿Hay alguna función que proporcione esta funcionalidad?Cómo invertir una lista en Java?

No deseo hacer ningún tipo de copia de la lista ni modificar la lista.

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 por mí mismo. Solo estoy preguntando si Java ya ofrece algo como esto.

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

que acaba de descubrir que algunas implementaciones tienen ListdescendingIterator() que es lo que necesito. Aunque no existe una implementación general de este tipo para List. Lo cual es un poco extraño porque la implementación que he visto en LinkedList es lo suficientemente general para funcionar con cualquier List.

+1

¿Puede construir la lista en el orden inverso para comenzar? –

+0

Sí lo hace - java.uitl.List.listIterator (int) http://download.oracle.com/javase/6/docs/api/java/util/List.html#listIterator%28int%29 – TofuBeer

Respuesta

151

Guava proporciona la siguiente: Lists.reverse(List)

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

A diferencia 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 en la lista original y la vista se reflejan en la otra.

+5

El problema es que la guayaba es una biblioteca muy grande Consulte la discusión: https://github.com/google/guava/issues/1954 y https://code.google.com/p/guava-libraries/issues/detail?id=605 –

+1

@Filipe de Lima Brito: ProGuard sigue siendo la mejor solución para el tamaño de la biblioteca, aunque es probable que podamos hacer mejoras. En cualquier caso, no creo que el tamaño de la biblioteca sea relevante de ninguna manera para esta respuesta. – ColinD

+1

Sí, el tamaño de la biblioteca no es relevante para esta respuesta, pero es relevante para ser informado por los programadores (¡por lo tanto, lo comenté)! ¡Muchas gracias por esta gran biblioteca y por su sugerencia @ColinD! –

23

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

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

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

java.util.Deque tiene descendingIterator() - si su List es a Deque, puede usar eso.

+0

Si no desea utilizar el método descndingIterator() incorporado, parece que usar ConcurrentLinkedDeque sería lo mejor para revertir una lista muy grande? Básicamente solo copie de una baraja a la nueva baraja usando encuestas y luego ofrezca? A Sorta le gusta tener una baraja de cartas y llevarse cada una de ellas en una pila nueva, en orden. – djangofan

173

Utilice 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 usa Colecciones.

Ergo,

Collections.reverse(list.clone()); 

Si está utilizando un List y no tiene acceso a clone() puede utilizar subList():

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

'clone()' normalmente crearía una copia de la lista. De todos modos, 'List # clone()' tampoco existe. – Albert

+6

Tiene razón técnica, la interfaz List no proporciona el método clone(). Pero ArrayList, LinkedList y Vector todo lo hacen. – jcalvert

+0

Clonar es una copia * superficial * de la lista. No copiará a los miembros. Pero creo que entiendo hacia dónde se dirige ahora, en referencia a una "vista", ya que cualquier cambio estructural en la 'vista' de subList() también altera el original. No creo que tengas manera de hacer lo que quieres sin crear una clase como lo hiciste en tu demo. – jcalvert

4

Sé que esto es una entrada 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 recomendado para largas Listas, 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.

+1

Su código tiene un problema: puede ponerle cualquier lista, pero siempre le devolverá ArrayList (como lista). ¿Y qué pasa si necesito LinkedList? Es mejor modificar myList y devolver vacío. –

+1

Tenga en cuenta que esto no es realmente lo que estaba pidiendo. Estaba pidiendo algún tipo de proxy/vista, no una copia. – Albert

1

También puede 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; 
} 
+5

Esa no es una vista de lista. Una vista es lo opuesto a una copia. – Albert

+0

La lista inversa de una lista vacía es nula ?? – ShellFish

68

si he entendido correctamente, entonces es una línea de código .Es trabajó para mí.

Collections.reverse(yourList); 
+6

Esa no es una vista de lista. Eso modifica la lista. – Albert

+1

oops Entendí mal .. –

+0

Esta respuesta acaba de venir: baja calidad: revisión. – Jayan

2

utilizo este:

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

} 

así:

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

Collections.reverse (nums) ... En realidad, invertir el orden de los elementos. A continuación 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); 

Collections.sort(nums); 

Collections.reverse(nums); 

System.out.println(nums); 
0

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

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

Para la lista de tamaño pequeño podemos crear LinkedList y luego se puede hacer uso de 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); // Four, Three, Two, One 
System.out.println(stringList); // One, Two, Three, Four