2011-02-08 1 views
50

Quindi sono ancora abbastanza nuovo a Java e sono stato a giocare con ArrayList di - quello che sto cercando di realizzare è un metodo per fare qualcosa di simile:Spostamento di elementi in giro in un ArrayList

Item 1 
Item 2 
Item 3 
Item 4 

Quindi sto cercando di essere in grado di spostare gli elementi nella lista, a meno che non sia già in alto, nel qual caso rimarrà lo stesso. Per esempio, se l'articolo 3 è stato spostato la lista sarebbe:

Item 1 
Item 3 
Item 2 
Item 4 

Dalla mia piccola comprensione in questo momento, allora vorrei qualcosa sulla falsariga di:

IF arrayname index is not equal to 0 
THEN move up 
ELSE do nothing 

La parte sto lottando con è la parte "sposta su". Tutti i suggerimenti o esempi di codice su come ciò potrebbe essere ottenuto sono molto apprezzati.

risposta

94

mi sono imbattuto in questa vecchia domanda nella mia ricerca di una risposta, e ho pensato di postare solo la soluzione che ho trovato nel caso in cui qualcun altro passa da qui cercando la stessa.

Per scambiare 2 elementi, Collections.swap va bene. Ma se vogliamo andare più elementi, c'è una soluzione migliore che comporta un uso creativo di Collections.sublist e Collections.rotate che non avevo pensato fino a quando ho visto descritto qui:

http://docs.oracle.com/javase/6/docs/api/java/util/Collections.html#rotate%28java.util.List,%20int%29

Ecco una citazione, ma andare lì e leggere tutto per te troppo:

si noti che questo metodo può essere utilmente applicato a sottoliste a spostare uno o più elementi all'interno di una lista, preservando l'ordine del rimanenti elementi.Ad esempio, il seguente linguaggio sposta l'elemento all'indice j avanti in posizione k (che deve essere maggiore o uguale a j):

Collections.rotate(list.subList(j, k+1), -1);

+2

Nella mia applicazione questa rotazione di sottolista è risultata più lenta dell'approccio remove/insert descritto qui: http://stackoverflow.com/a/4938696/1025391 – moooeeeep

+2

'maggiore o uguale (> =)'? che dire '<='? – user25

15

Per spostarsi verso l'alto, rimuovere e quindi aggiungere.

Per rimuovere - ArrayList.remove e assegnare l'oggetto restituito a una variabile
Poi aggiungere questo oggetto nuovamente in corrispondenza dell'indice richiesto - ArrayList.add(int index, E element)

http://download.oracle.com/javase/6/docs/api/java/util/ArrayList.html#add(int, E)

+2

Questa è l'unica soluzione che funziona davvero per modificare l'ordine di elementi in ArrayList. Grazie! – mpemburn

+1

Davvero molto elegante! – geekQ

+0

con la rimozione non si muove, sta cambiando le posizioni di due oggetti (scambio), spostando - sta spostando un oggetto tra altri due oggetti – user25

52

Un semplice scambio è molto meglio per " muoversi qualcosa" in un ArrayList:

if(i > 0) { 
    Item toMove = arrayList.get(i); 
    arrayList.set(i, arrayList.get(i-1)); 
    arrayList.set(i-1, toMove); 
} 

Perché un ArrayList utilizza una matrice, se si rimuove un elemento da un ArrayList, deve "spostare" tutti gli elementi dopo quell'elemento verso l'alto per riempire il vuoto nell'array. Se inserisci un elemento, deve spostare tutti gli elementi dopo quell'elemento per fare spazio per inserirlo. Questi spostamenti possono essere molto costosi se il tuo array è molto grande. Dato che sai che vuoi finire con lo stesso numero di elementi nella lista, fare uno scambio come questo ti permette di "spostare" un elemento in un'altra posizione nella lista in modo molto efficiente.

Come Chris Buckler e Michal Kreuzman sottolineano, v'è anche un metodo pratico in classe collezioni di ridurre queste tre righe di codice a uno:

Collections.swap(arrayList, i, i-1); 
+0

Questo è grandioso, collections.swap sembra essere perfetto. Un piccolo problema che ho notato è che l'uso di questo qualcosa in cima alla lista causa un'eccezione fuori limite - funziona ancora esattamente come volevo ma c'è un modo per impedirlo di lanciare un'eccezione fuori dai limiti? – user319940

+1

@ user319940 Hi StriplingWarrior lo ha mostrato nel primo codice di esempio. Indice Devo essere maggiore di 0 'se (i> 0)' –

+0

heh, sciocco me lo stavo provando mentre invece di se - grazie ancora una volta a tutti. Spero che questo post aiuti anche gli altri in futuro. – user319940

23

si può provare questo semplice codice, Collections.swap (lista, io, j) è quello che stai cercando.

List<String> list = new ArrayList<String>(); 
    list.add("1"); 
    list.add("2"); 
    list.add("3"); 
    list.add("4"); 

    String toMoveUp = "3"; 
    while (list.indexOf(toMoveUp) != 0) { 
     int i = list.indexOf(toMoveUp); 
     Collections.swap(list, i, i - 1); 
    } 

    System.out.println(list); 
+2

+1 per l'utilizzo dell'approccio generico. – Sid

0

elemento mobile rispetto all'altro è qualcosa Avevo bisogno di molto in un mio progetto. Così ho scritto una piccola classe util che sposta un elemento in una lista in una posizione relativa a un altro elemento. Sentitevi liberi di usare (e migliorare;))

import java.util.List; 

public class ListMoveUtil 
{ 
    enum Position 
    { 
     BEFORE, AFTER 
    }; 

    /** 
    * Moves element `elementToMove` to be just before or just after `targetElement`. 
    * 
    * @param list 
    * @param elementToMove 
    * @param targetElement 
    * @param pos 
    */ 
    public static <T> void moveElementTo(List<T> list, T elementToMove, T targetElement, Position pos) 
    { 
     if (elementToMove.equals(targetElement)) 
     { 
      return; 
     } 
     int srcIndex = list.indexOf(elementToMove); 
     int targetIndex = list.indexOf(targetElement); 
     if (srcIndex < 0) 
     { 
      throw new IllegalArgumentException("Element: " + elementToMove + " not in the list!"); 
     } 
     if (targetIndex < 0) 
     { 
      throw new IllegalArgumentException("Element: " + targetElement + " not in the list!"); 
     } 
     list.remove(elementToMove); 

     // if the element to move is after the targetelement in the list, just remove it 
     // else the element to move is before the targetelement. When we removed it, the targetindex should be decreased by one 
     if (srcIndex < targetIndex) 
     { 
      targetIndex -= 1; 
     } 
     switch (pos) 
     { 
      case AFTER: 
       list.add(targetIndex + 1, elementToMove); 
       break; 
      case BEFORE: 
       list.add(targetIndex, elementToMove); 
       break; 
     } 
    } 
3

Applicando la ricorsione per riordinare gli elementi in un arraylist

public class ArrayListUtils { 
      public static <T> void reArrange(List<T> list,int from, int to){ 
       if(from != to){ 
        if(from > to) 
         reArrange(list,from -1, to); 
         else 
         reArrange(list,from +1, to); 

        Collections.swap(list, from, to); 
       } 
      } 
    } 
2

Come pubblicato Mikkel prima Collections.rotate è un modo semplice. Sto usando questo metodo per spostare gli elementi verso l'alto e verso il basso in una lista.

public static <T> void moveItem(int sourceIndex, int targetIndex, List<T> list) { 
    if (sourceIndex <= targetIndex) { 
     Collections.rotate(list.subList(sourceIndex, targetIndex + 1), -1); 
    } else { 
     Collections.rotate(list.subList(targetIndex, sourceIndex + 1), 1); 
    } 
} 
1

Per Move elemento in lista è sufficiente aggiungere:

// move item to index 0 
Object object = ObjectList.get(index); 
ObjectList.remove(index); 
ObjectList.add(0,object); 

To Swap due elementi nella lista semplicemente aggiungere:

// swap item 10 with 20 
Collections.swap(ObjectList,10,20);