2010-10-18 41 views
160

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

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.

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


Ngoài ra, tôi biết cách tự thực hiện việc này. Tôi chỉ hỏi nếu Java đã cung cấp một cái gì đó như thế này.

Demo thực hiện:

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 chỉ đã phát hiện ra rằng một số List triển khai có descendingIterator() đó là những gì tôi cần. Mặc dù không có triển khai chung như vậy cho List. Đó là loại kỳ lạ bởi vì việc thực hiện tôi đã thấy trong LinkedList là đủ chung để làm việc với bất kỳ List.

+1

Bạn có thể tạo danh sách theo thứ tự ngược lại để bắt đầu không? –

+0

Có nó - java.uitl.List.listIterator (int) http://download.oracle.com/javase/6/docs/api/java/util/List.html#listIterator%28int%29 – TofuBeer

Trả lời

151

Guava cung cấp này: Lists.reverse(List)

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 xem ... nó không làm thay đổi thứ tự các phần 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 gốc khác.

+5

Vấn đề là rằng ổi là một thư viện rất lớn. Xem phần thảo luận: https://github.com/google/guava/issues/1954 và https://code.google.com/p/guava-libraries/issues/detail?id=605 –

+1

@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ó khả năng cải tiến mà 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 là có liên quan trong bất kỳ cách nào để trả lời này. – ColinD

+1

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! –

23

của nó không chính xác tao nhã, nhưng nếu bạn sử dụng List.listIterator (chỉ số int), bạn có thể nhận được một 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() 
} 
4

java.util.DequedescendingIterator() - nếu bạn là List a Deque, bạn có thể sử dụng nó.

+0

Nếu bạn không muốn sử dụng phương thức descndingIterator() dựng sẵn, có vẻ như sử dụng ConcurrentLinkedDeque 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 boong đến boong mới bằng cách sử dụng thăm dò ý kiến ​​sau đó cung cấp? Phân loại như chỉ có một cỗ bài và đưa mỗi đầu ra một đống mới, theo thứ tự. – djangofan

173

Sử dụng phương thức .clone() trên Danh sách của bạn. Nó sẽ trả về một bản sao nông, có nghĩa là nó sẽ chứa các con trỏ đến cùng một đố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 một List và không có quyền truy cập vào clone() bạn có thể sử dụng subList():

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

'clone()' bình 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

Về mặt kỹ thuật, chính giao diện Danh sách không cung cấp phương thức clone(). Nhưng ArrayList, LinkedList và Vector đều làm. – jcalvert

+0

Bản sao là bản sao * nông * của danh sách. Nó sẽ không sao chép các thành viên. Nhưng tôi nghĩ rằng tôi hiểu nơi bạn đang đi với điều này bây giờ, trong tham chiếu đến một "xem", như bất kỳ thay đổi cấu trúc để 'xem' từ subList() làm thay đổi bản gốc là tốt. Tôi không nghĩ rằng bạn có bất kỳ cách nào để làm những gì bạn muốn mà không tạo ra một lớp như bạn đã làm trong demo của bạn. – jcalvert

4

Tôi biết đây là một bài 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 khuyến nghị cho danh sách dài, điều này không được tối ưu hóa chút nào. Đó là một giải pháp dễ dàng cho các kịch bản được kiểm soát (danh sách tôi xử lý không có nhiều hơn 100 phần tử).

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

+1

Mã của bạn có một vấn đề - bạn có thể đặt bất kỳ Danh sách nào vào 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. –

+1

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/xem, không phải là một bản sao. – Albert

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à chế độ xem danh sách. Một cái nhìn ngược lại với một bản sao. – Albert

+0

Danh sách đảo ngược của một danh sách trống là null ?? – ShellFish

68

Nếu tôi đã hiểu đúng thì nó là một dòng mã Nó làm việc cho tôi.

Collections.reverse(yourList); 
+6

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

+1

oops Tôi hiểu sai .. –

+0

Câu trả lời này chỉ đến: chất lượng thấp: đánh giá. – Jayan

2

tôi sử dụng 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 
6

Collections.reverse (nums) ... Nó thực sự đảo ngược thứ tự của các yếu tố. Dưới mã nên được nhiều đánh giá cao -

List<Integer> nums = new ArrayList<Integer>(); 
nums.add(61); 
nums.add(42); 
nums.add(83); 
nums.add(94); 
nums.add(15); 

Collections.sort(nums); 

Collections.reverse(nums); 

System.out.println(nums); 
0

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

Đối với danh sách có kích thước nhỏ, chúng tôi có thể tạo LinkedList và sau đó có thể sử dụng giảm dần iterator như:

List<String> stringList = new ArrayList<>(Arrays.asList("One", "Two", "Three")); 
stringList.stream().collect(Collectors.toCollection(LinkedList::new)) 
     .descendingIterator(). 
     forEachRemaining(System.out::println); // Four, Three, Two, One 
System.out.println(stringList); // One, Two, Three, Four 
Các vấn đề liên quan