Qual é a maneira mais simples de reverter uma ArrayList?

333

Qual é a maneira mais simples de reverter esse 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
fonte

Respostas:

798
Collections.reverse(aList);

Exemplo ( referência ):

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
fonte
2
@AgarwalShankar Estou recebendo um erro necessário ArrayList encontrado nulo. Estou esquecendo de algo.
Sagar Devanga
9
@SagarDevanga A lista é revertida no lugar, não retornada.
Carcigenicate
Collections.reverse (Lista); Eu usei em um projeto Android, funciona bem.
Damir Varevac 07/07
22

Não é a maneira mais simples, mas se você é um fã de recursão, pode estar interessado no seguinte método para reverter um ArrayList:

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

Ou não 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
fonte
Posso estar errado, mas no seu exemplo não recursivo, não int jé atualizado a cada iteração? Você o inicializa, j = list.size() - 1mas não acho que a seção de inicializaçãofor loop seja atualizada a cada iteração, pois não?
Tony Chan
O @Turbo j não precisa ser atualizado a cada iteração. É inicializado no último índice do ArrayList e é usado para acessar o último elemento. Dentro do loop for, o último elemento é removido e inserido no índice i; i é incrementado até atingir a próxima a última posição no ArrayList.
Todd
1
Sim, mas na segunda iteração, você não receberá um IndexOutOfBoundsExceptiondesde que está tentando acessar j(o último índice do ArrayList original), mas você já removeu o objeto nesse índice?
Tony Chan
1
Desculpe, apenas executei o código, definitivamente funciona. Eu esqueci que add()empurra os outros elementos para baixo na matriz, para que a matriz permaneça essencialmente com um tamanho constante. Soluções interessantes, obrigado!
Tony Chan
Além disso, apenas curioso, mas como você criou o método recursivo? Eu não acho que isso é algo que eu normalmente pensaria.
Tony Chan
13

O truque aqui é definir "reverso". É possível modificar a lista no local, criar uma cópia na ordem inversa ou criar uma exibição na ordem inversa.

A maneira mais simples, intuitivamente falando , é Collections.reverse:

Collections.reverse(myList);

Este método modifica a lista no local . Ou seja, Collections.reversepega a lista e sobrescreve seus elementos, deixando para trás nenhuma cópia irreversível. Isso é adequado para alguns casos de uso, mas não para outros; além disso, assume que a lista é modificável. Se isso é aceitável, estamos bem.


Caso contrário, pode-se criar uma cópia na ordem inversa :

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

Essa abordagem funciona, mas requer a repetição da lista duas vezes. O construtor copy ( new ArrayList<>(list)) itera sobre a lista, e o mesmo acontece Collections.reverse. Podemos reescrever esse método para iterar apenas uma vez, se quisermos:

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

Isso é mais eficiente, mas também mais detalhado.

Como alternativa, podemos reescrever o item acima para usar a streamAPI do Java 8 , que algumas pessoas consideram mais concisa e legível que a 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
}

nb. isso Collectors.toList()faz muito poucas garantias sobre a lista de resultados. Se você deseja garantir que o resultado volte como um ArrayList, use-o Collectors.toCollection(ArrayList::new).


A terceira opção é criar uma visão em ordem inversa . Essa é uma solução mais complicada e digna de mais leituras / sua própria pergunta. O método de inversão de listas da Goiaba é um ponto de partida viável.

A escolha de uma implementação "mais simples" é deixada como um exercício para o leitor.

naomimyselfandi
fonte
6

Solução sem usar ArrayList extra ou combinação dos métodos add () e remove (). Ambos podem ter um impacto negativo se você precisar reverter uma 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;
 }
contraponto
fonte
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
fonte
2

Invertendo um ArrayList de maneira recursiva e sem criar uma nova lista para adicionar 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
fonte
1

Apenas no caso de estarmos usando o Java 8 , podemos usar o Stream. O ArrayList é uma lista de acesso aleatório e podemos obter um fluxo de elementos na ordem inversa e depois coletá-lo em um novo 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;
    }

A abordagem acima não é adequada para o LinkedList, pois não é de acesso aleatório. Também podemos usar instanceofpara verificar também.

akhil_mittal
fonte
1

Também podemos fazer o mesmo usando o 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
fonte
0

Um pouco mais legível :)

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
fonte
0

Outra solução 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
fonte