在ArrayList中移动项目


77

我一直在玩ArrayLists。我想要实现的是一种执行以下操作的方法:

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

我苦苦挣扎的部分是“向上移动”部分。如何实现此目标的任何技巧或代码示例都将受到赞赏。

Answers:


131

我在寻找答案时遇到了这个老问题,我以为我会发布找到的解决方案,以防其他人经过这里寻找相同的解决方案。

对于交换2个元素,Collections.swap很好。但是,如果我们想移动更多元素,则有一个更好的解决方案,涉及创造性地使用Collections.sublist和Collections.rotate,直到在这里看到它时我才想到:

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

这是报价,但也去那里自己读一遍:

请注意,此方法可以有效地应用于子列表,以在保留剩余元素顺序的同时在列表中移动一个或多个元素。例如,以下成语将索引j处的元素向前移动到位置k(其必须大于或等于j):

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


3
在我的应用程序中,此子列表的轮换似乎比此处描述的删除/插入方法慢:stackoverflow.com/a/4938696/1025391
moooeeeep

2
greater than or equal (>=)?那又如何<=呢?
user25年

68

一个简单的交换对于在ArrayList中“向上移动”要好得多:

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

因为ArrayList使用数组,所以如果您从ArrayList中删除一个项目,则必须向上移动该项目之后的所有元素以填充数组中的空白。如果插入项目,则必须移动该项目之后的所有元素以腾出空间来插入它。如果您的阵列很大,这些转换可能会变得非常昂贵。由于您知道最终要使用列表中相同数量的元素,因此执行这样的交换可以使您高效地将元素“移动”到列表中的另一个位置。

正如Chris Buckler和Michal Kreuzman指出的那样,Collections类中甚至还有一个方便的方法可以将以下三行代码减少为一行:

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

太好了,collections.swap似乎很完美。香港专业教育学院注意到的一个小问题是,在列表的顶部使用此东西会导致超出范围的异常-它仍然按我想要的方式工作,但是有什么方法可以阻止它抛出超出范围的异常?
user319940 2011年

1
@ user319940嗨StriplingWarrior在第一个代码示例中显示了它。索引我必须大于0if(i > 0)
michal.kreuzman 2011年

嘿,愚蠢的我,尝试了一段时间而不是如果-再次感谢大家。希望这篇文章将来也会对其他人有所帮助。
user319940 2011年

5
这仅在您仅将单个索引值上移某项时才有效。如果必须向上或向下移动某个索引值以上的值,则交换不再有用,事情会变得有些棘手。
Javid Jamae

1
@Javid Jamae:的确,如果您需要将元素移动一个以上的空间,这并不是那么简单。但是,它仍然比删除和重新添加元素要有效得多。如果您要进行大量移动,则绝对建议使用LinkedList。
StriplingWarrior

31

您可以尝试这个简单的代码,Collections.swap(list,i,j)是您想要的。

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

25

要向上移动,请先删除然后再添加。

删除-ArrayList.remove并将返回的对象分配给变量,
然后将该对象添加回所需的索引处-ArrayList.add(int index, E element)

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


2
这是唯一可以实际更改ArrayList中项目顺序的解决方案。谢谢!
mpemburn

2
确实很优雅!
geekQ '16

1
删除它不会移动,它正在更改两个对象的位置(交换),正在移动-它正在其他两个对象之间移动一个对象
user25

10

正如Mikkel在Collections.rotate之前发布的那样,这是一种简单的方法。我正在使用这种方法在列表中上下移动项目。

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

5

将递归应用于数组列表中的项的重新排序

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

5

Move在列表中添加项目,只需添加:

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

Swap在列表中的两个项目只需添加:

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

ObjectList.remove(index)返回删除的对象,因此您可以摆脱之前的行。只要使其成为Object object = Objectlist.remove(index);
约书亚

0

在我的项目中,我非常需要相对于彼此移动元素。因此,我编写了一个小的util类,将列表中的元素移动到相对于另一个元素的位置。随时使用(并改进;))

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

0

Kotlin解决方案,可将元素从“ fromPos”移动到“ toPos”,并相应地移动所有其他项(用于在Android应用程序中以交错布局recyclerView移动项)

            if(fromPos < toPos){                    
                val movingElement = myList[fromPos]
                //shifts all elements between fromPos and toPos 1 down
                for(i in fromPos+1..toPos){
                    myList[i-1] = myList[i]
                }
                //re-add element that was saved in the beginning
                myList[toPos] = movingElement
            }

            if(fromPos > toPos){
                val movingElement = myList[fromPos]
                //shifts elements between toPos and fromPos 1 up
                for(i in fromPos downTo toPos+1){
                    myList[i] = myList[i-1]
                }                    
                //re-add element that was saved in the beginning
                myList[toPos] = movingElement
            }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.