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.