Làm thế nào để có được một khung nhìn danh sách đảo ngược trên một danh sách trong Java?


214

Tôi muốn có chế độ xem danh sách đảo ngược trong danh sách (theo cách tương tự như List#sublistcung cấp chế độ xem danh sách phụ trong danh sách). Có một số chức năng cung cấp chức năng này?

Tôi không muốn tạo bất kỳ loại bản sao nào của danh sách cũng như không sửa đổi danh sách.

Nó sẽ là đủ nếu tôi có thể nhận được ít nhất một trình vòng lặp ngược trong danh sách trong trường hợp này.


Ngoài ra, tôi biết làm thế nào để thực hiện điều này bản thân mình. Tôi chỉ hỏi rằng Java đã cung cấp một cái gì đó như thế này chưa.

Thực hiện demo:

static <T> Iterable<T> iterableReverseList(final List<T> l) {
    return new Iterable<T>() {
        public Iterator<T> iterator() {
            return new Iterator<T>() {
                ListIterator<T> listIter = l.listIterator(l.size());                    
                public boolean hasNext() { return listIter.hasPrevious(); }
                public T next() { return listIter.previous(); }
                public void remove() { listIter.remove(); }                 
            };
        }
    };
}

Tôi đã phát hiện ra rằng một số Listtriển khai có descendingIterator()những gì tôi cần. Mặc dù không có thực hiện chung như vậy cho List. Điều này là lạ vì thực hiện tôi đã thấy LinkedListlà đủ để làm việc với bất kỳ List.


1
Bạn có thể xây dựng danh sách theo thứ tự ngược lại để bắt đầu không?
Tony Enni

Có nó - java.uitl.List.listIterator (int) download.oracle.com/javase/6/docs/api/java/util/...
TofuBeer

Nếu bạn truy cập liên kết này để tìm câu trả lời làm thế nào để đảo ngược (sửa đổi) danh sách, đây là câu trả lời:Collections.reverse(list)
ZhaoGang

Câu trả lời:


209

Quả ổi cung cấp cái này: Lists.reverse (Danh sách)

List<String> letters = ImmutableList.of("a", "b", "c");
List<String> reverseView = Lists.reverse(letters); 
System.out.println(reverseView); // [c, b, a]

Không giống như Collections.reverse, đây hoàn toàn là một khung nhìn ... nó không làm thay đổi thứ tự các yếu tố trong danh sách ban đầu. Ngoài ra, với danh sách gốc có thể sửa đổi, các thay đổi đối với cả danh sách gốc và chế độ xem được phản ánh trong danh sách khác.


11
Vấn đề là Guava là một thư viện rất lớn. Xem cuộc thảo luận: github.com/google/guava/issues/1954code.google.com/p/guava-lologists/issues/detail?id=605
Filipe Brito

2
@Filipe de Lima Brito: ProGuard vẫn là giải pháp tốt nhất cho kích thước thư viện, mặc dù có nhiều khả năng chúng tôi có thể thực hiện. Trong mọi trường hợp, tôi không nghĩ rằng kích thước thư viện có liên quan theo bất kỳ cách nào cho câu trả lời này.
ColinD

2
Có, kích thước thư viện không liên quan đến câu trả lời này, nhưng có liên quan để được thông báo cho các lập trình viên (do đó, tôi đã nhận xét)! Cảm ơn bạn rất nhiều vì thư viện tuyệt vời này và cho đề xuất của bạn @ColinD!
Filipe Brito

@ColinD, yup, đó là sai lầm của tôi. Một đồng nghiệp đã thêm các bộ sưu tập google cũng có cùng không gian tên và lớp ( List) nhưng không có phương thức ngược lại. loại bỏ nó làm cho ổi có sẵn một lần nữa.
AaA

Các nhà phát triển không phải lúc nào cũng có quyền kiểm soát những thư viện nào họ có thể sử dụng và thêm một thư viện hoàn toàn mới cho những thứ đơn giản như vậy là quá mức - đặc biệt là vấn đề có thể được giải quyết vớiListIterator.previous()
Jonathan Benn

218

Sử dụng phương thức .clone () trong Danh sách của bạn. Nó sẽ trả về một bản sao nông, nghĩa là nó sẽ chứa các con trỏ tới cùng các đối tượng, vì vậy bạn sẽ không phải sao chép danh sách. Sau đó, chỉ cần sử dụng Bộ sưu tập.

Ergo

Collections.reverse(list.clone());

Nếu bạn đang sử dụng Listvà không có quyền truy cập, clone()bạn có thể sử dụng subList():

List<?> shallowCopy = list.subList(0, list.size());
Collections.reverse(shallowCopy);

21
clone()thông thường sẽ tạo một bản sao của danh sách. Dù sao, List#clone()cũng không tồn tại.
Albert

6
Bạn đúng về mặt kỹ thuật, bản thân giao diện List không cung cấp phương thức clone (). Nhưng ArrayList, LinkedList và Vector đều làm được.
jcalvert

2
Tôi chỉ nhìn lên việc thực hiện clone(). Nó thực sự là một bản sao đầy đủ của danh sách (nó chỉ không sao chép từng đối tượng duy nhất trong danh sách nhưng đó không bao giờ là điều tôi đang nói về).
Albert

21
Lưu ý rằng Collections.reverse trả về void, vì vậy bạn sẽ mất tham chiếu bản sao. Bạn cần gán bản sao cho một biến trước, sau đó sắp xếp nó.
12722

10
subListkhông sao chép, nó chỉ cung cấp một khung nhìn trên danh sách bên dưới, do đó đảo ngược khung nhìn này sẽ đảo ngược danh sách bên dưới.
Roland

80

Nếu tôi đã hiểu đúng thì đó là một dòng mã. Nó hoạt động với tôi.

 Collections.reverse(yourList);

12
Đó không phải là một danh sách xem. Điều đó sửa đổi danh sách.
Albert

35

Nó không chính xác thanh lịch, nhưng nếu bạn sử dụng List.listIterator (int index), bạn có thể nhận được ListIterator hai chiều đến cuối danh sách:

//Assume List<String> foo;
ListIterator li = foo.listIterator(foo.size());

while (li.hasPrevious()) {
   String curr = li.previous()
}

1
Đây là câu trả lời tốt nhất, vì (1) nó không yêu cầu thư viện và (2) nó không sửa đổi danh sách ban đầu, như OP yêu cầu
Jonathan Benn

12

Bộ sưu tập.reverse (nums) ... Nó thực sự đảo ngược thứ tự của các phần tử. Mã dưới đây nên được đánh giá cao -

List<Integer> nums = new ArrayList<Integer>();
nums.add(61);
nums.add(42);
nums.add(83);
nums.add(94);
nums.add(15);
//Tosort the collections uncomment the below line
//Collections.sort(nums); 

Collections.reverse(nums);

System.out.println(nums);

Đầu ra: 15,94,83,42,61


8
Bạn chỉ đang lặp lại câu trả lời mà người khác đã viết 6 năm trước
Jonathan Benn

1
... và không phải là một góc nhìn. Điều này làm thay đổi danh sách.
Jason S

6

java.util.DequedescendingIterator()- nếu bạn Listlà một Deque, bạn có thể sử dụng nó.


Nếu bạn không muốn sử dụng phương thức descinatingIterator () tích hợp, có vẻ như sử dụng một concurrencyLinkedDeque sẽ là cách tốt nhất để đảo ngược một danh sách rất lớn? Về cơ bản chỉ cần sao chép từ một bộ bài sang bộ bài mới bằng cách sử dụng thăm dò ý kiến? Sắp xếp giống như chỉ có một cỗ bài và lấy từng lá trên cùng thành một đống mới, theo thứ tự.
djangofan

4

Tôi biết đây là một bài viết cũ nhưng hôm nay tôi đã tìm kiếm một cái gì đó như thế này. Cuối cùng, tôi đã tự viết mã:

private List reverseList(List myList) {
    List invertedList = new ArrayList();
    for (int i = myList.size() - 1; i >= 0; i--) {
        invertedList.add(myList.get(i));
    }
    return invertedList;
}

Không được đề xuất cho Danh sách dài, điều này hoàn toàn không được tối ưu hóa. Đó là một giải pháp dễ dàng cho các tình huống được kiểm soát (Danh sách tôi xử lý không có hơn 100 yếu tố).

Hy vọng nó sẽ giúp được ai đó.


2
Mã của bạn có một vấn đề - bạn có thể đặt bất kỳ Danh sách nào cho nó, nhưng nó sẽ luôn trả về cho bạn ArrayList (dưới dạng Danh sách). Và nếu tôi cần LinkedList thì sao? Tốt hơn là sửa đổi myList và trả về void.
Dmitry Zaytsev

2
Lưu ý rằng đây không thực sự là những gì tôi đã yêu cầu. Tôi đã yêu cầu một số loại proxy / lượt xem, không phải là một bản sao.
Albert

4

Tôi sử dụng cái này:

public class ReversedView<E> extends AbstractList<E>{

    public static <E> List<E> of(List<E> list) {
        return new ReversedView<>(list);
    }

    private final List<E> backingList;

    private ReversedView(List<E> backingList){
        this.backingList = backingList;
    }

    @Override
    public E get(int i) {
        return backingList.get(backingList.size()-i-1);
    }

    @Override
    public int size() {
        return backingList.size();
    }

}

như thế này:

ReversedView.of(backingList) // is a fully-fledged generic (but read-only) list

1

Bạn cũng có thể làm điều này:

static ArrayList<String> reverseReturn(ArrayList<String> alist)
{
   if(alist==null || alist.isEmpty())
   { 
       return null;
   }

   ArrayList<String> rlist = new ArrayList<>(alist);

   Collections.reverse(rlist);
   return rlist;
}

5
Đó không phải là một danh sách xem. Một cái nhìn ngược lại với một bản sao.
Albert

Danh sách ngược của danh sách trống là null ??
ShellFish

1

Bạn cũng có thể đảo ngược vị trí khi bạn yêu cầu một đối tượng:

Object obj = list.get(list.size() - 1 - position);

1

Đối với danh sách có kích thước nhỏ, chúng ta có thể tạo LinkedListvà sau đó có thể sử dụng trình lặp giảm dần như:

List<String> stringList = new ArrayList<>(Arrays.asList("One", "Two", "Three"));
stringList.stream().collect(Collectors.toCollection(LinkedList::new))
         .descendingIterator().
         forEachRemaining(System.out::println); // Three, Two, One
System.out.println(stringList); // One, Two, Three

-3

Sử dụng reverse(...)phương pháp của java.util.Collectionslớp. Vượt qua danh sách của bạn dưới dạng tham số và danh sách của bạn sẽ bị đảo ngược.

Collections.reverse(list);

1
Bản sao của một câu trả lời hiện có
Karl Richter
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.