Java'daki bir listede ters liste görünümü nasıl alınır?


214

Bir listede ters liste görünümü olmasını istiyorum (listede bir alt liste List#sublistgörünümü sağlar gibi). Bu işlevi sağlayan bazı işlevler var mı?

Listenin herhangi bir kopyasını almak veya listeyi değiştirmek istemiyorum.

Bu durumda bir listede en azından ters bir yineleyici alabilsem yeterli olurdu.


Ayrıca, bunu kendim nasıl uygulayacağımı biliyorum. Sadece Java'nın zaten böyle bir şey sağlayıp sağlamadığını soruyorum.

Demo uygulaması:

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

Sadece bazı Listuygulamaların descendingIterator()ihtiyacım olan şey olduğunu öğrendim. Genel bir uygulama olmamasına rağmen List. Bu biraz garip çünkü gördüğüm uygulama LinkedListherhangi biriyle çalışmak için yeterince genel List.


1
Başlamak için listeyi ters sırayla oluşturabilir misiniz?
Tony Ennis

Evet öyle - java.uitl.List.listIterator (int) download.oracle.com/javase/6/docs/api/java/util/…
TofuBeer

Listeyi nasıl tersine çevireceğinizi (değiştireceğiniz) cevabı bulmak için bu bağlantıyı ziyaret ederseniz, cevap budur:Collections.reverse(list)
ZhaoGang

Yanıtlar:


210

Guava bunu sağlar: Lists.reverse (Liste)

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

Bunun aksine Collections.reverse, bu sadece bir görünümdür ... orijinal listedeki öğelerin sırasını değiştirmez. Ayrıca, değiştirilebilir orijinal bir listeyle, hem orijinal listede hem de görünümde yapılan değişiklikler diğerine yansıtılır.


11
Sorun şu ki, Guava çok büyük bir kütüphane. Tartışmaya bakın: github.com/google/guava/issues/1954 ve code.google.com/p/guava-libraries/issues/detail?id=605
Filipe Brito

2
@Filipe de Lima Brito: ProGuard, kütüphane boyutu için hala en iyi çözümdür, ancak yapabileceğimiz iyileştirmeler olabilir. Her halükarda, kütüphane boyutunun bu cevapla hiçbir şekilde alakalı olduğunu düşünmüyorum.
ColinD

2
Evet, kütüphane boyutu bu cevapla ilgili değildir, ancak programcılar için bilgilendirilmekle ilgilidir (bu nedenle yorum yaptım)! Bu harika kütüphane ve önerileriniz için çok teşekkür ederim @ColinD!
Filipe Brito

@ColinD, evet, bu benim hatamdı. Bir meslektaşım aynı ad alanına ve class'a ( List) sahip olan ancak ters yöntemi olmayan google koleksiyonları ekledi . kaldırılması guava'yı tekrar kullanılabilir hale getirdi.
AaA

Geliştiriciler her zaman hangi kütüphaneleri kullanabilecekleri üzerinde kontrole sahip değildir ve bu kadar basit bir şey için tamamen yeni bir kütüphane eklemek aşırıya kaçmak gibi görünüyor - özellikle sorunun çözülebileceği göz önüne alındığında ListIterator.previous()
Jonathan Benn

218

Listenizdeki .clone () yöntemini kullanın. Sığ bir kopya döndürür, yani aynı nesnelere işaretçiler içereceğinden listeyi kopyalamanız gerekmez. Ardından Koleksiyonlar'ı kullanın.

Ergo,

Collections.reverse(list.clone());

A kullanıyorsanız Listve erişiminiz clone()yoksa şunları kullanabilirsiniz subList():

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

21
clone()normalde listenin bir kopyasını oluşturur. Her neyse, List#clone()de yok.
Albert

6
Teknik olarak haklısınız, List arabiriminin kendisi clone () yöntemini sağlamıyor. Ancak ArrayList, LinkedList ve Vector hepsi yapar.
jcalvert

2
Sadece uygulamasına baktım clone(). Gerçekten listenin tam bir kopyasını yapar (sadece listedeki her bir nesneyi klonlamaz, ancak asla bahsettiğim şey değildi).
Albert

21
Collections.reverse değerinin geçersiz döndürdüğünü unutmayın, böylece klon başvurusunu kaybedersiniz. Önce klonu bir değişkene atamanız, sonra sıralamanız gerekir.
user12722

10
subListkopyalanmaz, yalnızca temel listede bir görünüm sağlar, bu nedenle bu görünümü tersine çevirmek temel listeyi tersine çevirir.
Roland

80

Eğer doğru anladıysam o zaman bir kod satırıdır. Benim için çalıştı.

 Collections.reverse(yourList);

12
Bu bir liste görünümü değil. Bu listeyi değiştirir.
Albert

35

Tam olarak zarif değil, ancak List.listIterator (int dizini) kullanırsanız, listenin sonuna iki yönlü bir ListIterator alabilirsiniz:

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

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

1
Bu en iyi yanıttır, çünkü (1) bir kütüphane gerektirmez ve (2) OP'nin istediği gibi orijinal listeyi değiştirmez
Jonathan Benn

12

Collections.reverse (nums) ... Aslında öğelerin sırasını tersine çevirir. Aşağıdaki kod çok takdir edilmelidir -

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

Çıktı: 15,94,83,42,61


8
Başka birinin yazdığı yanıtı 6 yıl önce tekrarlıyorsunuz
Jonathan Benn

1
... bir görüş değil. bu listeyi değiştirir.
Jason S

6

java.util.Dequevardır descendingIterator()- eğer Listbir ise Deque, bunu kullanabilirsiniz.


Yerleşik descndingIterator () yöntemini kullanmak istemediyseniz, ConcurrentLinkedDeque kullanmak çok büyük bir listeyi tersine çevirmek için en iyisi olur mu? Temelde sadece bir desteden yeni güverteye anketi kullanarak kopyala, sonra teklif et? Sorta sadece bir deste desteye sahip olmak ve sırayla her birini yeni bir kazığa çıkarmak gibi.
djangofan

4

Bunun eski bir yazı olduğunu biliyorum ama bugün böyle bir şey arıyordum. Sonunda kodu kendim yazdı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;
}

Uzun Listeler için önerilmez, bu hiç optimize edilmez. Kontrollü senaryolar için kolay bir çözümdür (Kullandığım Listelerin 100'den fazla öğesi yoktur).

Umarım birine yardımcı olur.


2
Kodunuzun bir sorunu var - buna herhangi bir Liste koyabilirsiniz, ancak her zaman size ArrayList (Liste olarak) döndürür. LinkedList'e ihtiyacım olursa ne olacak? MyList'ini değiştirmek ve void'i döndürmek daha iyidir.
Dmitry Zaytsev

2
Bunun gerçekten istediğim şey olmadığını unutmayın. Ben bir kopya değil, bir tür proxy / görünüm istiyordu.
Albert

4

Bunu kullanıyorum:

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

}

bunun gibi:

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

1

Bunu da yapabilirsiniz:

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
Bu bir liste görünümü değil. Görünüm, kopyanın tersidir.
Albert

Boş listenin ters listesi null ??
ShellFish

1

Ayrıca, bir nesne talep ettiğinizde konumu tersine çevirebilirsiniz:

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

1

Küçük boyutlu liste için aşağıdaki LinkedListgibi inen yineleyiciyi oluşturabilir ve kullanabiliriz:

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

Kullanım reverse(...)yöntemleri java.util.Collectionssınıfına. Listenizi parametre olarak ilettiğinizde listeniz tersine çevrilir.

Collections.reverse(list);

1
Mevcut bir cevabın kopyası
Karl Richter
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.