Verschieben von Elementen in einer ArrayList

75

Ich habe mit ArrayLists rumgespielt. Was ich erreichen möchte, ist eine Methode, um so etwas zu tun:

Item 1
Item 2
Item 3
Item 4

Ich versuche, Elemente in der Liste nach oben verschieben zu können, es sei denn, sie befinden sich bereits oben. In diesem Fall bleibt sie gleich. Wenn beispielsweise Element 3 verschoben wurde, lautet die Liste wie folgt:

Item 1
Item 3
Item 2
Item 4

Nach meinem kleinen Verständnis im Moment würde ich dann etwas in der Art von wollen:

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

Der Teil, mit dem ich zu kämpfen habe, ist der "Aufstieg" -Teil. Alle Tipps oder Codebeispiele, wie dies erreicht werden könnte, werden sehr geschätzt.

user319940
quelle

Antworten:

130

Ich bin auf diese alte Frage gestoßen, als ich nach einer Antwort gesucht habe, und dachte, ich würde nur die Lösung posten, die ich gefunden habe, falls jemand anderes hier vorbeikommt und nach der gleichen sucht.

Für den Austausch von 2 Elementen ist Collections.swap in Ordnung. Wenn wir jedoch mehr Elemente verschieben möchten, gibt es eine bessere Lösung, die eine kreative Verwendung von Collections.sublist und Collections.rotate beinhaltet, an die ich erst gedacht hatte, als ich sie hier beschrieben sah:

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

Hier ist ein Zitat, aber gehen Sie dorthin und lesen Sie das Ganze auch selbst:

Beachten Sie, dass diese Methode sinnvoll auf Unterlisten angewendet werden kann, um ein oder mehrere Elemente innerhalb einer Liste zu verschieben, während die Reihenfolge der verbleibenden Elemente beibehalten wird. Zum Beispiel bewegt das folgende Idiom das Element am Index j vorwärts zur Position k (die größer oder gleich j sein muss):

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

Mikkel
quelle
3
In meiner Anwendung schien diese Unterlistenrotation langsamer zu sein als der hier beschriebene Ansatz zum Entfernen / Einfügen: stackoverflow.com/a/4938696/1025391
moooeeeep
2
greater than or equal (>=)? was ist mit <=?
Benutzer25
68

Ein einfacher Austausch ist weitaus besser, um in einer ArrayList etwas nach oben zu verschieben:

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

Da eine ArrayList ein Array verwendet, müssen beim Entfernen eines Elements aus einer ArrayList alle Elemente nach diesem Element nach oben "verschoben" werden, um die Lücke im Array zu füllen. Wenn Sie ein Element einfügen, müssen alle Elemente nach diesem Element verschoben werden, um Platz zum Einfügen zu schaffen. Diese Verschiebungen können sehr teuer werden, wenn Ihr Array sehr groß ist. Da Sie wissen, dass Sie die gleiche Anzahl von Elementen in der Liste haben möchten, können Sie durch einen solchen Austausch ein Element sehr effizient an eine andere Stelle in der Liste "verschieben".

Wie Chris Buckler und Michal Kreuzman hervorheben, gibt es in der Collections-Klasse sogar eine praktische Methode, um diese drei Codezeilen auf eine zu reduzieren:

Collections.swap(arrayList, i, i-1);
StriplingWarrior
quelle
Das ist großartig, collection.swap scheint perfekt zu sein. Ein kleines Problem, das mir aufgefallen ist, ist, dass die Verwendung dieses Problems oben in der Liste eine Ausnahme außerhalb der Grenzen verursacht - es funktioniert immer noch genau so, wie ich es wollte, aber gibt es eine Möglichkeit, es zu verhindern, dass eine Ausnahme außerhalb der Grenzen ausgelöst wird?
user319940
1
@ user319940 Hi StriplingWarrior hat es im ersten Codebeispiel gezeigt. Index Ich muss größer als 0 seinif(i > 0)
michal.kreuzman
heh, dumm von mir, habe es mit while versucht anstatt mit if - nochmals vielen Dank an alle. Hoffentlich hilft dieser Beitrag auch in Zukunft anderen.
user319940
4
Dies funktioniert nur, wenn Sie nur einen einzigen Indexwert nach oben verschieben. Wenn Sie etwas um mehr als einen Indexwert nach oben oder unten verschieben müssen, ist ein Swap nicht mehr sinnvoll und die Dinge werden etwas schwieriger.
Javid Jamae
1
@Javid Jamae: Es ist wahr, dass es nicht so einfach ist, wenn Sie das Element um mehr als ein Leerzeichen verschieben müssen. Es ist jedoch immer noch weitaus effizienter als das Entfernen und erneute Hinzufügen des Elements. Wenn Sie sich viel bewegen, würde ich auf jeden Fall eine LinkedList empfehlen.
StriplingWarrior
31

Sie können diesen einfachen Code ausprobieren. Collections.swap (list, i, j) ist genau das, wonach Sie suchen.

    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);
michal.kreuzman
quelle
25

Zum Aufsteigen entfernen und dann hinzufügen.

So entfernen Sie - ArrayList.remove und weisen das zurückgegebene Objekt einer Variablen zu.
Fügen Sie dieses Objekt dann wieder am erforderlichen Index hinzu.ArrayList.add(int index, E element)

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

Amol Katdare
quelle
2
Dies ist die einzige Lösung, die tatsächlich funktioniert, um die Reihenfolge der Elemente in der ArrayList zu ändern. Vielen Dank!
mpemburn
2
Sehr elegant!
GeekQ
1
mit dem Entfernen bewegt es sich nicht, es ändert die Positionen von zwei Objekten (tauschen), bewegt sich - es bewegt ein Objekt zwischen zwei anderen Objekten
user25
10

Wie Mikkel vor Collections.rotate gepostet hat, ist dies ein einfacher Weg. Ich verwende diese Methode, um Elemente in einer Liste nach oben und unten zu verschieben.

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);
    }
}
Marwils
quelle
5

Anwenden der Rekursion zum Neuordnen von Elementen in einer Arrayliste

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);
                }
            }
    }
Michel Durieux
quelle
5

Zum MoveEintrag in der Liste fügen Sie einfach hinzu:

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

Zu Swapzwei Elementen in der Liste fügen Sie einfach hinzu:

// swap item 10 with 20
Collections.swap(ObjectList,10,20);
Amir Hossein Ghasemi
quelle
ObjectList.remove (Index) gibt das entfernte Objekt zurück, sodass Sie die Zeile zuvor entfernen können. Machen Sie es einfach Object object = Objectlist.remove (index);
JoshuaD
0

Das Bewegen von Elementen in Bezug aufeinander ist etwas, das ich in einem meiner Projekte sehr brauchte. Also habe ich eine kleine util-Klasse geschrieben, die ein Element in einer Liste an eine Position relativ zu einem anderen Element verschiebt. Fühlen Sie sich frei zu verwenden (und zu verbessern;))

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