Как получить перевернутый вид списка в списке на 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

Гуава обеспечивает это: 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
Проблема в том, что Guava - очень большая библиотека. Смотрите обсуждение: github.com/google/guava/issues/1954 и code.google.com/p/guava-libraries/issues/detail?id=605
Брито

2
@ Филипе де Лима Брито: ProGuard по-прежнему является лучшим решением для размера библиотеки, хотя есть вероятные улучшения, которые мы можем сделать. В любом случае, я не думаю, что размер библиотеки имеет какое-либо отношение к этому ответу.
ColinD

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

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

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

218

Используйте метод .clone () в своем списке. Он вернет поверхностную копию, что означает, что он будет содержать указатели на те же объекты, поэтому вам не придется копировать список. Тогда просто используйте Коллекции.

Ergo,

Collections.reverse(list.clone());

Если вы используете Listи не имеете доступа, clone()вы можете использовать subList():

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

21
clone()обычно создаст копию списка. Во всяком случае, List#clone()также не существует.
Альберт

6
Вы технически правы, сам интерфейс List не предоставляет метод clone (). Но ArrayList, LinkedList и Vector все делают.
jcalvert

2
Я только что посмотрел реализацию clone(). Это действительно делает полную копию списка (он не только клонирует каждый отдельный объект в списке, но это никогда не было тем, о чем я говорил).
Альберт

21
Обратите внимание, что Collections.reverse возвращает void, поэтому вы потеряете ссылку на клон. Вам необходимо сначала присвоить клон переменной, а затем отсортировать ее.
user12722

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) он не изменяет исходный список, как того требует OP
Джонатан Бенн

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
... и не вид. это мутирует список.
Джейсон С

6

java.util.Dequeесть descendingIterator()- если ваш Listесть Deque, вы можете использовать.


Если вы не хотите использовать встроенный метод descndingIterator (), кажется, что использование ConcurrentLinkedDeque было бы лучшим для обращения к очень большому списку? В основном просто скопировать из одной колоды в новую колоду, используя опрос, а затем предложить? Сорту нравится просто иметь колоду карт и брать каждого с вершины в новую кучу, по порядку.
Джангофан

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 (как список). А что если мне нужен LinkedList? Лучше изменить myList и вернуть void.
Дмитрий Зайцев

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.