在数组列表中移动项

我一直在使用 ArrayList,我想要实现的是这样一种方法:

Item 1
Item 2
Item 3
Item 4

我试图能够移动的项目在清单上,除非它已经在顶部,在这种情况下,它将保持不变。例如,如果项目3被移动,列表将是:

Item 1
Item 3
Item 2
Item 4

根据我目前的一点了解,我想要的是这样的东西:

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

我纠结的是“往上爬”这部分。关于如何实现这一点的任何提示或代码示例都非常值得赞赏。

165525 次浏览

To move up, remove and then add.

To remove - ArrayList.remove and assign the returned object to a variable
Then add this object back at the required index -ArrayList.add(int index, E element)

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

A simple swap is far better for "moving something up" in an ArrayList:

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

Because an ArrayList uses an array, if you remove an item from an ArrayList, it has to "shift" all the elements after that item upward to fill in the gap in the array. If you insert an item, it has to shift all the elements after that item to make room to insert it. These shifts can get very expensive if your array is very big. Since you know that you want to end up with the same number of elements in the list, doing a swap like this allows you to "move" an element to another location in the list very efficiently.

As Chris Buckler and Michal Kreuzman point out, there is even a handy method in the Collections class to reduce these three lines of code to one:

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

you can try this simple code, Collections.swap(list, i, j) is what you looking for.

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

I came across this old question in my search for an answer, and I thought I would just post the solution I found in case someone else passes by here looking for the same.

For swapping 2 elements, Collections.swap is fine. But if we want to move more elements, there is a better solution that involves a creative use of Collections.sublist and Collections.rotate that I hadn't thought of until I saw it described here:

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

Here's a quote, but go there and read the whole thing for yourself too:

Note that this method can usefully be applied to sublists to move one or more elements within a list while preserving the order of the remaining elements. For example, the following idiom moves the element at index j forward to position k (which must be greater than or equal to j):

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

Moving element with respect to each other is something I needed a lot in a project of mine. So I wrote a small util class that moves an element in an list to a position relative to another element. Feel free to use (and improve upon ;))

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

Applying recursion to reorder items in an 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);
}
}
}

As Mikkel posted before Collections.rotate is a simple way. I'm using this method for moving items up- and downward in a List.

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

To Move item in list simply add:

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

To Swap two items in list simply add:

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

Start from toIndex and shift nearby elements until it reaches fromIndex. Finally set element at fromIndex to toIndex.

fun <E> ArrayList<E>.move(fromIndex: Int, toIndex: Int) {
if (fromIndex >= size || fromIndex < 0) {
throw IndexOutOfBoundsException(outOfBoundsMsg(fromIndex, size))
}
if (toIndex >= size || toIndex < 0) {
throw IndexOutOfBoundsException(outOfBoundsMsg(toIndex, size))
}
if (fromIndex == toIndex) return
var index = toIndex
var item = get(index)
if (fromIndex > toIndex) {
while (index < fromIndex) {
index++
item = set(index, item)
}
} else {
while (index > fromIndex) {
index--
item = set(index, item)
}
}
set(toIndex, item)
}


private fun outOfBoundsMsg(index: Int, size: Int): String {
return "Index: $index, Size: $size"
}