Як отримати переглянуте перегляд списку у списку на Java?


214

Я хочу мати у списку переглянуте перегляд (аналогічним чином, ніж List#sublistу списку подання переліку). Чи є якась функція, яка забезпечує цю функціональність?

Я не хочу робити жодної копії списку і не змінювати її.

Було б досить, якби я міг отримати хоча б зворотний ітератор у списку в цьому випадку.


Також я знаю, як це реалізувати самостійно. Я просто запитую, чи Java вже надає щось подібне.

Демонстраційна реалізація:

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

Щойно я виявив, що в деяких Listреалізаціях descendingIterator()є те, що мені потрібно. Хоча загальної такої реалізації не існує List. Що дивно, тому що реалізація, яку я бачив LinkedList, досить загальна для роботи з будь-якою List.


1
Чи можете ви спочатку побудувати список у зворотному порядку?
Тоні Енніс

Так, це - java.uitl.List.listIterator (int) download.oracle.com/javase/6/docs/api/java/util/…
TofuBeer

Якщо ви завітаєте на це посилання, щоб знайти відповідь, як повернути (змінити) список, це відповідь:Collections.reverse(list)
ZhaoGang

Відповіді:


210

Guava надає це: Lists.reverse (Список)

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

На відміну від Collections.reverseцього, це суто вигляд ... це не змінює впорядкованість елементів у вихідному списку. Крім того, із оригінальним списком, який може змінюватися, зміни і в початковому списку, і в перегляд відображаються в іншому.


11
Проблема в тому, що Гуава - це дуже велика бібліотека. Дивіться дискусію: github.com/google/guava/isissue/1954 та code.google.com/p/guava-libraries/isissue/detail?id=605
Filipe Brito

2
@Filipe de Lima Brito: ProGuard як і раніше є найкращим рішенням щодо розміру бібліотеки, хоча, можливо, ми можемо зробити покращення. У будь-якому випадку, я не думаю, що розмір бібліотеки жодним чином не відповідає цій відповіді.
ColinD

2
Так, розмір бібліотеки не відповідає цій відповіді, але є релевантним для інформування для програмістів (тому я прокоментував)! Дуже дякую за цю чудову бібліотеку та за вашу пропозицію @ColinD!
Філіпе Бріто

@ColinD, так, це була моя помилка. Колега додав google-колекції, які також мають однаковий простір імен та клас ( List), але без зворотного методу. видаливши його, знову зробила доступ гуавою.
AaA

Розробники не завжди мають контроль над тим, якими бібліотеками вони можуть користуватися, і додавання цілої нової бібліотеки для чогось такого простого здається зайвим - особливо зважаючи на те, що проблему можна вирішитиListIterator.previous()
Джонатан Бенн

218

Використовуйте метод .clone () у своєму списку. Він поверне дрібну копію, що означає, що вона буде містити покажчики на ті самі об’єкти, тому вам не доведеться копіювати список. Тоді просто використовуйте Колекції.

Ерго,

Collections.reverse(list.clone());

Якщо ви використовуєте a Listі не маєте доступу до clone()вас, ви можете використовувати subList():

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

21
clone()зазвичай створюється копія списку. У всякому разі, List#clone()також не існує.
Альберт

6
Ви технічно праві, сам інтерфейс списку не забезпечує метод clone (). Але ArrayList, LinkedList та Vector все це роблять.
jcalvert

2
Я просто подивився на реалізацію clone(). Він дійсно робить повну копію списку (він лише не клонує кожен окремий об'єкт у списку, але про це я ніколи не говорив).
Альберт

21
Зауважте, що Collections.reverse повертає недійсно, так що ви втратите посилання на клон. Потрібно спершу призначити клон змінній, а потім сортувати її.
користувач12722

10
subListне копіює, він просто надає перегляд основного списку, тому перейменування цього подання буде перетворювати підсумковий список.
Роланд

80

Якщо я зрозумів правильно, то це один рядок коду. Він працював на мене.

 Collections.reverse(yourList);

12
Це не перегляд списку. Це змінює список.
Альберт

35

Це не зовсім елегантно, але якщо ви використовуєте List.listIterator (int index), ви можете отримати двонаправлений ListIterator до кінця списку:

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

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

1
Це найкраща відповідь, оскільки (1) вона не потребує бібліотеки, і (2) вона не змінює оригінальний список, як просив ОП
Джонатан Бенн

12

Collections.reverse (nums) ... Це насправді змінює порядок елементів. Нижче код повинен бути високо оцінений -

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

Вихід: 15,94,83,42,61


8
Ви просто повторюєте відповідь, яку написав ще хтось 6 років тому
Джонатан Бенн

1
... а не вид. це вимкнення списку.
Jason S

6

java.util.Dequeмає descendingIterator()- якщо ваше Listє Deque, ви можете використовувати це.


Якщо ви не хочете використовувати вбудований метод descndingIterator (), схоже, що використання ConcurrentLinkedDeque було б найкращим способом змінити дуже великий список? В основному просто скопіюйте з однієї колоди на нову колоду, використовуючи опитування, тоді пропонуйте? Сорта любить просто мати колоду карт і знімати кожен зверху в нову купу, за порядком.
djangofan

4

Я знаю, що це стара публікація, але сьогодні я шукав щось подібне. Врешті-решт я сам написав код:

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

Не рекомендується для довгих списків, це зовсім не оптимізовано. Це якесь просте рішення для керованих сценаріїв (списки, з якими я оброблюю, мають не більше 100 елементів).

Сподіваюся, це комусь допоможе.


2
У вашого коду є одна проблема - ви можете помістити до нього будь-який список, але він завжди поверне вам ArrayList (як List). А що, якщо мені потрібен LinkedList? Краще змінити мій список і повернути ніщо.
Дмитро Зайцев

2
Зауважте, що це насправді не те, про що я просив. Я просив про якийсь проксі / перегляд, а не про копію.
Альберт

4

Я використовую це:

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

}

подобається це:

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

1

Ви також можете зробити це:

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
Це не перегляд списку. Вид - це протилежність копії.
Альберт

Зворотний список порожнього списку є нульовим ??
ShellFish

1

Ви також можете перевернути позицію, коли запитуєте об’єкт:

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

1

Для невеликого розміру списку ми можемо створити, LinkedListа потім використати ітератор, що спадає, як:

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

Використовуйте reverse(...)методи java.util.Collectionsкласу. Передайте свій список як параметр, і ваш список повернеться назад.

Collections.reverse(list);

1
Копія наявної відповіді
Карл Ріхтер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.