Как получить перевернутый вид списка в списке на 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этого, это просто представление ... оно не меняет порядок элементов в исходном списке. Кроме того, с исходным списком, который можно изменить, изменения как исходного списка, так и представления отражаются в другом.

ColinD
источник
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);
jcalvert
источник
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()
}
kkress
источник
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, вы можете использовать.

Bozho
источник
Если вы не хотите использовать встроенный метод 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 элементов).

Надеюсь, это кому-нибудь поможет.

CocheLee
источник
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
Museful
источник
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;
}
jhdrosos
источник
5
Это не представление списка. Представление является противоположностью копии.
Альберт
Обратный список пустого списка является нулевым ??
ShellFish
1

Вы также можете инвертировать позицию при запросе объекта:

Object obj = list.get(list.size() - 1 - position);
fede1608
источник
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
akhil_mittal
источник
-3

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

Collections.reverse(list);
Шубхо Гош
источник
1
Копия существующего ответа
Карл Рихтер