Di chuyển các mục xung quanh trong ArrayList


77

Tôi đã chơi xung quanh với ArrayLists. Những gì tôi đang cố gắng đạt được là một phương pháp để làm điều gì đó như sau:

Item 1
Item 2
Item 3
Item 4

Tôi đang cố gắng di chuyển các mục lên trong danh sách, trừ khi nó đã ở trên cùng, trong trường hợp đó nó sẽ giữ nguyên. Ví dụ: nếu mục 3 được di chuyển, danh sách sẽ là:

Item 1
Item 3
Item 2
Item 4

Từ hiểu biết nhỏ của tôi vào lúc này, tôi muốn một cái gì đó dọc theo dòng:

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

Phần tôi đang gặp khó khăn là phần "di chuyển lên". Bất kỳ mẹo hoặc mẫu mã nào về cách đạt được điều này đều được đánh giá cao.

Câu trả lời:


131

Tôi đã gặp câu hỏi cũ này trong quá trình tìm kiếm câu trả lời và tôi nghĩ tôi sẽ chỉ đăng giải pháp mà tôi tìm thấy trong trường hợp có người khác đi ngang qua đây cũng tìm kiếm câu trả lời tương tự.

Để hoán đổi 2 phần tử, Collections.swap là được. Nhưng nếu chúng tôi muốn di chuyển nhiều yếu tố hơn, có một giải pháp tốt hơn liên quan đến việc sử dụng sáng tạo Collections.sublist và Collections.rotate mà tôi chưa nghĩ đến cho đến khi tôi thấy nó được mô tả ở đây:

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

Đây là một trích dẫn, nhưng hãy đến đó và đọc toàn bộ nội dung cho chính bạn:

Lưu ý rằng phương pháp này có thể được áp dụng một cách hữu ích cho danh sách con để di chuyển một hoặc nhiều phần tử trong danh sách mà vẫn giữ nguyên thứ tự của các phần tử còn lại. Ví dụ, thành ngữ sau đây di chuyển phần tử ở chỉ số j về phía trước đến vị trí k (phải lớn hơn hoặc bằng j):

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


3
Trong ứng dụng của tôi xoay sublist này dường như là chậm hơn so với phương thức remove / insert-phương pháp mô tả ở đây: stackoverflow.com/a/4938696/1025391
moooeeeep

2
greater than or equal (>=)? thì <=sao?
25

68

Một hoán đổi đơn giản sẽ tốt hơn nhiều cho việc "di chuyển thứ gì đó lên" trong ArrayList:

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

Bởi vì ArrayList sử dụng một mảng, nếu bạn xóa một mục khỏi ArrayList, nó phải "dịch chuyển" tất cả các phần tử sau mục đó lên trên để lấp đầy khoảng trống trong mảng. Nếu bạn chèn một mục, nó phải di chuyển tất cả các phần tử sau mục đó để có chỗ để chèn nó. Những thay đổi này có thể rất tốn kém nếu mảng của bạn rất lớn. Vì bạn biết rằng bạn muốn kết thúc bằng cùng một số phần tử trong danh sách, việc hoán đổi như vậy cho phép bạn "di chuyển" một phần tử đến một vị trí khác trong danh sách rất hiệu quả.

Như Chris Buckler và Michal Kreuzman đã chỉ ra, thậm chí còn có một phương pháp hữu ích trong lớp Collections để giảm ba dòng mã này thành một:

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

Điều này thật tuyệt vời, collection.swap dường như là hoàn hảo. Một vấn đề nhỏ mà tôi nhận thấy là việc sử dụng một thứ gì đó ở đầu danh sách gây ra ngoại lệ ngoài giới hạn - nó vẫn hoạt động theo cách tôi muốn nhưng có cách nào để ngăn nó ném ra ngoại lệ ngoài giới hạn không?
user319940

1
@ user319940 Xin chào StriplingWarrior đã hiển thị nó trong mẫu mã đầu tiên. Chỉ số i phải lớn hơn 0if(i > 0)
michal.kreuzman

heh, tôi ngớ ngẩn, đã thử nó với trong khi thay vì if - một lần nữa cảm ơn mọi người. Hy vọng rằng bài đăng này cũng sẽ giúp ích cho những người khác trong tương lai.
user319940

5
Điều này chỉ hoạt động nếu bạn đang di chuyển thứ gì đó lên chỉ một giá trị chỉ mục duy nhất. Nếu bạn phải di chuyển thứ gì đó lên hoặc xuống nhiều hơn một giá trị chỉ mục, hoán đổi sẽ không còn hữu ích nữa và mọi thứ trở nên phức tạp hơn một chút.
Javid Jamae

1
@Javid Jamae: Đúng là không đơn giản nếu bạn cần di chuyển phần tử nhiều hơn một khoảng trắng. Tuy nhiên, nó vẫn hiệu quả hơn nhiều so với việc xóa và thêm lại phần tử. Nếu bạn đang di chuyển nhiều mục, tôi chắc chắn khuyên bạn nên sử dụng LinkedList.
StriplingWarrior

31

bạn có thể thử mã đơn giản này, Collections.swap (list, i, j) là những gì bạn đang tìm kiếm.

    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

Để di chuyển lên, hãy xóa và sau đó thêm.

Để loại bỏ - ArrayList.remove và gán đối tượng trả về cho một biến
Sau đó thêm đối tượng này trở lại chỉ mục cần thiết -ArrayList.add(int index, E element)

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


2
Đây là giải pháp duy nhất thực sự hoạt động để thay đổi thứ tự của các mục trong ArrayList. Cảm ơn!
mpemburn

2
Quả thực rất thanh lịch!
geekQ

1
với việc loại bỏ nó sẽ không di chuyển, nó thay đổi vị trí của hai đối tượng (hoán đổi), di chuyển - nó đang di chuyển một đối tượng giữa một số hai đối tượng khác
dùng

10

Như Mikkel đã đăng trước Collections.rotate là một cách đơn giản. Tôi đang sử dụng phương pháp này để di chuyển các mục lên và xuống trong Danh sách.

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

Áp dụng đệ quy để sắp xếp lại các mục trong danh sách mảng

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

Đối với Movemục trong danh sách, chỉ cần thêm:

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

Đối với Swaphai mục trong danh sách, chỉ cần thêm:

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

ObjectList.remove (index) trả về đối tượng đã bị xóa, vì vậy bạn có thể loại bỏ dòng trước đó. Chỉ cần làm cho nó Đối tượng đối tượng = Objectlist.remove (chỉ mục);
JoshuaD

0

Yếu tố di chuyển đối với nhau là điều tôi cần rất nhiều trong một dự án của mình. Vì vậy, tôi đã viết một lớp sử dụng nhỏ để di chuyển một phần tử trong danh sách đến một vị trí liên quan đến một phần tử khác. Hãy thoải mái sử dụng (và cải thiện sau;))

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

Giải pháp Kotlin để di chuyển một Phần tử từ "fromPos" sang "toPos" và chuyển tất cả các mục khác cho phù hợp (hữu ích cho việc di chuyển một mục trong một tái chế bố cục so le trong một ứng dụng Android)

            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
            }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.