Was ist der einfachste Weg, eine ArrayList umzukehren?

333

Was ist der einfachste Weg, um diese ArrayList umzukehren?

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
quelle

Antworten:

796
Collections.reverse(aList);

Beispiel ( Referenz ):

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
quelle
2
@AgarwalShankar Ich erhalte einen Fehler erforderlich ArrayList gefunden ungültig. Vermisse ich etwas?
Sagar Devanga
9
@SagarDevanga Die Liste wird an Ort und Stelle umgekehrt und nicht zurückgegeben.
Carcigenicate
Collections.reverse (Liste); Ich habe es in einem Android-Projekt verwendet, funktioniert gut.
Damir Varevac
Es kehrt meine Elemente nicht um ...
22

Nicht der einfachste Weg, aber wenn Sie ein Fan von Rekursion sind, könnte Sie die folgende Methode zum Umkehren einer ArrayList interessieren:

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

Oder nicht rekursiv:

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
quelle
Ich könnte mich irren, aber wird in Ihrem nicht rekursiven Beispiel int jnicht bei jeder Iteration aktualisiert? Sie initialisieren es auf, j = list.size() - 1aber ich glaube nicht, dass der Initialisierungsabschnitt von for loopmit jeder Iteration aktualisiert wird, oder?
Tony Chan
@Turbo j muss nicht bei jeder Iteration aktualisiert werden. Es wird mit dem letzten Index der ArrayList initialisiert und für den Zugriff auf das letzte Element verwendet. Innerhalb der for-Schleife wird das letzte Element entfernt und in den Index i eingefügt. i wird erhöht, bis es die vorletzte Position in der ArrayList erreicht.
Todd
1
Ja, aber bei der zweiten Iteration erhalten Sie keine, IndexOutOfBoundsExceptionda Sie versuchen, auf jden letzten Index der ursprünglichen ArrayList zuzugreifen, aber Sie haben das Objekt an diesem Index bereits entfernt?
Tony Chan
1
Sorry, habe gerade den Code ausgeführt, funktioniert definitiv. Ich habe vergessen, dass add()die anderen Elemente im Array nach unten gedrückt werden, sodass das Array im Wesentlichen eine konstante Größe hat. Interessante Lösungen, danke!
Tony Chan
Auch nur neugierig, aber wie sind Sie auf die rekursive Methode gekommen? Ich glaube nicht, dass ich normalerweise daran denken würde.
Tony Chan
13

Der Trick hier ist die Definition von "umgekehrt". Sie können die Liste an Ort und Stelle ändern, eine Kopie in umgekehrter Reihenfolge erstellen oder eine Ansicht in umgekehrter Reihenfolge erstellen.

Der einfachste Weg, intuitiv zu sprechen , ist Collections.reverse:

Collections.reverse(myList);

Diese Methode ändert die vorhandene Liste . Das heißt, Collections.reversenimmt die Liste und überschreibt ihre Elemente, wobei keine nicht rückgängig gemachte Kopie zurückbleibt. Dies ist für einige Anwendungsfälle geeignet, für andere jedoch nicht. Außerdem wird davon ausgegangen, dass die Liste geändert werden kann. Wenn das akzeptabel ist, sind wir gut.


Wenn nicht, könnte man eine Kopie in umgekehrter Reihenfolge erstellen :

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

Dieser Ansatz funktioniert, erfordert jedoch ein zweimaliges Durchlaufen der Liste. Der Kopierkonstruktor ( new ArrayList<>(list)) durchläuft die Liste und dies auch Collections.reverse. Wir können diese Methode so umschreiben, dass sie nur einmal wiederholt wird, wenn wir dazu neigen:

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

Dies ist effizienter, aber auch ausführlicher.

Alternativ können wir das oben Gesagte umschreiben, um die streamAPI von Java 8 zu verwenden , die einige Leute prägnanter und lesbarer finden als die oben genannten:

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. Das Collectors.toList()gibt nur sehr wenige Garantien für die Ergebnisliste. Wenn Sie sicherstellen möchten, dass das Ergebnis als ArrayList zurückgegeben wird, verwenden Sie Collectors.toCollection(ArrayList::new)stattdessen.


Die dritte Option besteht darin , eine Ansicht in umgekehrter Reihenfolge zu erstellen . Dies ist eine kompliziertere Lösung und verdient eine weitere Lektüre / eine eigene Frage. Die umgekehrte Methode von Guavas Listen # ist ein praktikabler Ausgangspunkt.

Die Auswahl einer "einfachsten" Implementierung bleibt dem Leser als Übung überlassen.

naomimyselfandi
quelle
6

Lösung ohne zusätzliche ArrayList oder Kombination von add () - und remove () -Methoden. Beides kann sich negativ auswirken, wenn Sie eine große Liste umkehren müssen.

 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;
 }
Contrapost
quelle
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
quelle
Das habe ich benutzt, danke!
2

Rekursives Umkehren einer ArrayList und ohne Erstellen einer neuen Liste zum Hinzufügen von Elementen:

   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
quelle
1

Nur für den Fall, dass wir Java 8 verwenden , können wir Stream verwenden. Die ArrayList ist eine Direktzugriffsliste, und wir können einen Strom von Elementen in umgekehrter Reihenfolge abrufen und ihn dann in einer neuen sammeln 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;
    }

Der obige Ansatz ist nicht für LinkedList geeignet, da dies kein Direktzugriff ist. Wir können auch nutzen, um dies instanceofzu überprüfen.

akhil_mittal
quelle
1

Wir können dasselbe auch mit Java 8 tun.

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

Ein bisschen lesbarer :)

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;
}
Ja
quelle
0

Eine andere rekursive Lösung

 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
quelle