¿Cuál es la forma más simple de revertir una ArrayList?

334

¿Cuál es la forma más simple de revertir esta ArrayList?

ArrayList<Integer> aList = new ArrayList<>();

//Add elements to ArrayList object
aList.add("1");
aList.add("2");
aList.add("3");
aList.add("4");
aList.add("5");

while (aList.listIterator().hasPrevious())
  Log.d("reverse", "" + aList.listIterator().previous());
Ishu
fuente

Respuestas:

799
Collections.reverse(aList);

Ejemplo ( referencia ):

ArrayList aList = new ArrayList();
//Add elements to ArrayList object
aList.add("1");
aList.add("2");
aList.add("3");
aList.add("4");
aList.add("5");
Collections.reverse(aList);
System.out.println("After Reverse Order, ArrayList Contains : " + aList);
Shankar Agarwal
fuente
2
@AgarwalShankar obtengo un error requerido ArrayList encontrado nulo. Me estoy perdiendo de algo.
Sagar Devanga
99
@SagarDevanga La lista se invierte en su lugar, no se devuelve.
Carcigenicate
Collections.reverse (Lista); Lo usé en un proyecto de Android, funciona bien.
Damir Varevac
22

No es la forma más simple, pero si eres fanático de la recursividad, es posible que te interese el siguiente método para revertir una ArrayList:

public ArrayList<Object> reverse(ArrayList<Object> list) {
    if(list.size() > 1) {                   
        Object value = list.remove(0);
        reverse(list);
        list.add(value);
    }
    return list;
}

O no recursivamente:

public ArrayList<Object> reverse(ArrayList<Object> list) {
    for(int i = 0, j = list.size() - 1; i < j; i++) {
        list.add(i, list.remove(j));
    }
    return list;
}
todd
fuente
Podría estar equivocado, pero en su ejemplo no recursivo, ¿ int jno se actualiza con cada iteración? Lo inicializa j = list.size() - 1pero no creo que la sección de inicialización del for loopse actualice con cada iteración, ¿verdad?
Tony Chan
@Turbo j no necesita actualizarse con cada iteración. Se inicializa en el último índice de ArrayList y se usa para acceder al último elemento. Dentro del bucle for, el último elemento se elimina y se inserta en el índice i; i se incrementa hasta que alcanza la penúltima posición en la ArrayList.
todd
1
Sí, pero en la segunda iteración, ¿no recibirá un IndexOutOfBoundsExceptionmensaje ya que está intentando acceder j(el último índice de la Lista de Array original) pero ya eliminó el objeto en ese índice?
Tony Chan
1
Lo siento, solo ejecuté el código, definitivamente funciona. Olvidé que add()empuja a los otros elementos hacia abajo en la matriz, por lo que la matriz permanece esencialmente un tamaño constante. Soluciones interesantes, gracias!
Tony Chan
Además, solo es curioso, pero ¿cómo se te ocurrió el método recursivo? No creo que sea algo en lo que normalmente pensaría.
Tony Chan
13

El truco aquí es definir "revertir". Se puede modificar la lista en su lugar, crear una copia en orden inverso o crear una vista en orden inverso.

La forma más simple, intuitivamente hablando , es Collections.reverse:

Collections.reverse(myList);

Este método modifica la lista en su lugar . Es decir, Collections.reversetoma la lista y sobrescribe sus elementos, sin dejar ninguna copia no invertida. Esto es adecuado para algunos casos de uso, pero no para otros; Además, se supone que la lista es modificable. Si esto es aceptable, estamos bien.


Si no, uno podría crear una copia en orden inverso :

static <T> List<T> reverse(final List<T> list) {
    final List<T> result = new ArrayList<>(list);
    Collections.reverse(result);
    return result;
}

Este enfoque funciona, pero requiere iterar sobre la lista dos veces. El constructor de copia ( new ArrayList<>(list)) itera sobre la lista, y también lo hace Collections.reverse. Podemos reescribir este método para iterar solo una vez, si estamos tan inclinados:

static <T> List<T> reverse(final List<T> list) {
    final int size = list.size();
    final int last = size - 1;

    // create a new list, with exactly enough initial capacity to hold the (reversed) list
    final List<T> result = new ArrayList<>(size);

    // iterate through the list in reverse order and append to the result
    for (int i = last; i >= 0; --i) {
        final T element = list.get(i);
        result.add(element);
    }

    // result now holds a reversed copy of the original list
    return result;
}

Esto es más eficiente, pero también más detallado.

Alternativamente, podemos reescribir lo anterior para usar la streamAPI de Java 8 , que algunas personas encuentran más concisa y legible que lo anterior:

static <T> List<T> reverse(final List<T> list) {
    final int last = list.size() - 1;
    return IntStream.rangeClosed(0, last) // a stream of all valid indexes into the list
        .map(i -> (last - i))             // reverse order
        .mapToObj(list::get)              // map each index to a list element
        .collect(Collectors.toList());    // wrap them up in a list
}

nótese bien. eso Collectors.toList()hace muy pocas garantías sobre la lista de resultados. Si desea asegurarse de que el resultado regrese como ArrayList, úselo en su Collectors.toCollection(ArrayList::new)lugar.


La tercera opción es crear una vista en orden inverso . Esta es una solución más complicada, y merece una lectura adicional / su propia pregunta. El método inverso de Listas de guayaba es un punto de partida viable.

La elección de una implementación "más simple" se deja como un ejercicio para el lector.

naomimyselfandi
fuente
6

Solución sin usar ArrayList adicional o combinación de métodos add () y remove (). Ambos pueden tener un impacto negativo si tiene que revertir una lista enorme.

 public ArrayList<Object> reverse(ArrayList<Object> list) {

   for (int i = 0; i < list.size() / 2; i++) {
     Object temp = list.get(i);
     list.set(i, list.get(list.size() - i - 1));
     list.set(list.size() - i - 1, temp);
   }

   return list;
 }
contrapuesto
fuente
5
ArrayList<Integer> myArray = new ArrayList<Integer>();

myArray.add(1);
myArray.add(2);
myArray.add(3);

int reverseArrayCounter = myArray.size() - 1;

for (int i = reverseArrayCounter; i >= 0; i--) {
    System.out.println(myArray.get(i));
}
Tolunay Guney
fuente
2

Invertir una ArrayList de forma recursiva y sin crear una nueva lista para agregar elementos:

   public class ListUtil {

    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<String>();
        arrayList.add("1");
        arrayList.add("2");
        arrayList.add("3");
        arrayList.add("4");
        arrayList.add("5");
        System.out.println("Reverse Order: " + reverse(arrayList));

    }

    public static <T> List<T> reverse(List<T> arrayList) {
        return reverse(arrayList,0,arrayList.size()-1);
    }
    public static <T> List<T> reverse(List<T> arrayList,int startIndex,int lastIndex) {

        if(startIndex<lastIndex) {
            T t=arrayList.get(lastIndex);
            arrayList.set(lastIndex,arrayList.get(startIndex));
            arrayList.set(startIndex,t);
            startIndex++;
            lastIndex--;
            reverse(arrayList,startIndex,lastIndex);
        }
        return arrayList;
    }

}
Joby Wilson Mathews
fuente
1

En caso de que estemos usando Java 8 , podemos hacer uso de Stream. ArrayList es una lista de acceso aleatorio y podemos obtener una secuencia de elementos en orden inverso y luego recopilarla en una nueva ArrayList.

public static void main(String[] args) {
        ArrayList<String> someDummyList = getDummyList();
        System.out.println(someDummyList);
        int size = someDummyList.size() - 1;
        ArrayList<String> someDummyListRev = IntStream.rangeClosed(0,size).mapToObj(i->someDummyList.get(size-i)).collect(Collectors.toCollection(ArrayList::new));
        System.out.println(someDummyListRev);
    }

    private static ArrayList<String> getDummyList() {
        ArrayList dummyList = new ArrayList();
        //Add elements to ArrayList object
        dummyList.add("A");
        dummyList.add("B");
        dummyList.add("C");
        dummyList.add("D");
        return dummyList;
    }

El enfoque anterior no es adecuado para LinkedList ya que no es de acceso aleatorio. También podemos hacer uso de instanceofpara comprobar también.

akhil_mittal
fuente
1

También podemos hacer lo mismo con Java 8.

public static<T> List<T> reverseList(List<T> list) {
        List<T> reverse = new ArrayList<>(list.size());

        list.stream()
                .collect(Collectors.toCollection(LinkedList::new))
                .descendingIterator()
                .forEachRemaining(reverse::add);

        return reverse;
    }
vijayraj34
fuente
0

Un poco más legible :)

public static <T> ArrayList<T> reverse(ArrayList<T> list) {
    int length = list.size();
    ArrayList<T> result = new ArrayList<T>(length);

    for (int i = length - 1; i >= 0; i--) {
        result.add(list.get(i));
    }

    return result;
}
Yas
fuente
0

Otra solucion recursiva

 public static String reverse(ArrayList<Float> list) {
   if (list.size() == 1) {
       return " " +list.get(0);
   }
   else {
       return " "+ list.remove(list.size() - 1) + reverse(list);
   } 
 }
dt94
fuente