Qual è il modo più semplice per invertire una matrice?


333

Qual è il modo più semplice per invertire questa 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());

Risposte:


798
Collections.reverse(aList);

Esempio ( riferimento ):

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

2
@AgarwalShankar sto ricevendo un errore richiesto ArrayList trovato vuoto. Mi sto perdendo qualcosa.
Sagar Devanga,

9
@SagarDevanga L'elenco è invertito in posizione, non restituito.
Carcigenicato,

Collections.reverse (Lista); L'ho usato in un progetto Android, funziona benissimo.
Damir Varevac,

22

Non è il modo più semplice ma se sei un fan della ricorsione potresti essere interessato al seguente metodo per invertire un 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 in modo non ricorsivo:

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

Potrei sbagliarmi, ma nel tuo esempio non ricorsivo, non ti int jaggiorni ad ogni iterazione? Lo inizializzi a j = list.size() - 1ma non penso che la sezione di inizializzazione della for loopvenga aggiornata con ogni iterazione lo fa?
Tony Chan,

@Turbo j non ha bisogno di essere aggiornato con ogni iterazione. Viene inizializzato sull'ultimo indice di ArrayList e viene utilizzato per accedere all'ultimo elemento. All'interno del ciclo for l'ultimo elemento viene rimosso e inserito nell'indice i; viene incrementato fino a raggiungere la posizione successiva all'ultima nell'ArrayList.
todd

1
Sì, ma nella seconda iterazione, non ne otterrai uno IndexOutOfBoundsExceptiondal momento che stai tentando di accedere j(l'ultimo indice dell'ArrayList originale) ma hai già rimosso l'oggetto in quell'indice?
Tony Chan,

1
Siamo spiacenti, ho appena eseguito il codice, sicuramente funziona. Ho dimenticato che add()spinge gli altri elementi verso il basso dell'array, quindi l'array rimane sostanzialmente di dimensioni costanti. Soluzioni interessanti, grazie!
Tony Chan,

Inoltre, solo curioso, ma come ti è venuto in mente il metodo ricorsivo? Non penso che sia qualcosa a cui normalmente penserei.
Tony Chan,

13

Il trucco qui sta definendo "reverse". È possibile modificare l'elenco in posizione, creare una copia in ordine inverso o creare una vista in ordine inverso.

Il modo più semplice, intuitivamente parlando , è Collections.reverse:

Collections.reverse(myList);

Questo metodo modifica l'elenco in atto . Cioè, Collections.reverseprende l'elenco e sovrascrive i suoi elementi, senza lasciare alcuna copia senza risposta. Questo è adatto per alcuni casi d'uso, ma non per altri; inoltre, presuppone che l'elenco sia modificabile. Se questo è accettabile, stiamo bene.


In caso contrario, si potrebbe creare una copia in ordine inverso :

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

Questo approccio funziona, ma richiede di ripetere due volte l'elenco. Il costruttore di copia ( new ArrayList<>(list)) scorre sull'elenco e così fa Collections.reverse. Possiamo riscrivere questo metodo per iterare solo una volta, se siamo così propensi:

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

Questo è più efficiente, ma anche più dettagliato.

In alternativa, possiamo riscrivere quanto sopra per utilizzare l' streamAPI di Java 8 , che alcune persone trovano più concisa e leggibile di quanto sopra:

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. che Collectors.toList()offre pochissime garanzie sull'elenco dei risultati. Se vuoi assicurarti che il risultato ritorni come ArrayList, usa Collectors.toCollection(ArrayList::new)invece.


La terza opzione è quella di creare una vista in ordine inverso . Questa è una soluzione più complicata e degna di ulteriori letture / la propria domanda. Liste di Guava # retro metodo è un valido punto di partenza.

La scelta di un'implementazione "più semplice" viene lasciata come esercizio per il lettore.


6

Soluzione senza utilizzare ArrayList extra o una combinazione di metodi add () e remove (). Entrambi possono avere un impatto negativo se si deve invertire un elenco 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;
 }

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

2

Invertire una ArrayList in modo ricorsivo e senza creare un nuovo elenco per l'aggiunta di elementi:

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

}

1

Nel caso in cui stiamo usando Java 8 , allora possiamo usare Stream. ArrayList è un elenco di accesso casuale e possiamo ottenere un flusso di elementi in ordine inverso e quindi raccoglierlo in un nuovo 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;
    }

L'approccio sopra non è adatto per LinkedList in quanto non è un accesso casuale. Possiamo anche usare instanceofper controllare pure.


1

Possiamo anche fare lo stesso usando 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;
    }

0

Un po 'più leggibile :)

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

0

Un'altra soluzione ricorsiva

 public static String reverse(ArrayList<Float> list) {
   if (list.size() == 1) {
       return " " +list.get(0);
   }
   else {
       return " "+ list.remove(list.size() - 1) + reverse(list);
   } 
 }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.