2017-02-14 16 views
4

LinkedList можно итерация, используя восходящий или нисходящий итератор, как это:descendingIterator для java.util.List

 LinkedList<Object> list = new LinkedList<Object>(); 
     ... 
    StringJoiner sJ1 = new StringJoiner(" "); 
    list.iterator().forEachRemaining(a -> sJ1.add(a.toString())); 
    System.out.println("averse: \n" + sJ1.toString()); 

    StringJoiner sJ2 = new StringJoiner(" "); 
    list.descendingIterator().forEachRemaining(a -> sJ2.add(a.toString())); 
    System.out.println("reverse: \n" + sJ2.toString()); 
averse: 
Hello 2 Chocolate 10 
reverse: 
10 Chocolate 2 Hello 

Но descendingIterator не доступна для Списка и ArrayList. Есть ли какое-либо обходное решение или объяснение в списке, почему descendingIterator отсутствует в Список?

Вопрос аналогичен Can one do a for each loop in java in reverse order?. Но все ответы рекомендуют специальные решения или сторонние библиотеки.

Возможно, это возможно, используя потоки потоков? (К сожалению, мой прибегая к помощи дает лишь отсутствие стандартного обратного потока для Java 8 stream reverse order)

Как я уже упоминал мои вопросы связан к тому, что о потоках, но:

  • Использование потока только вариант, речь идет о java.util.Iterator и java.util.List
  • Ответы на этот вопрос решены только в частичном случае, но показали отсутствие удобного общего обратного хода. Если я не пропущу, список List упорядочен, сортировка элементов сравнения, для достижения порядка уменьшает объем.
+0

Возможный дубликат [обратного порядка потока Java 8] (http://stackoverflow.com/questions/24010109/java-8-stream-reverse-order) – Andremoniy

+1

Возможно, вы просто хотите использовать 'ArrayDeque' вместо' ArrayList'? – Holger

ответ

1

Я вижу два возможных решения здесь:

Используйте Intstream, чтобы создать поток, который проходит список в обратном порядке:

IntStream.range(0, list.length()) 
    .mapToObj(i -> list.get(list.length() - i - 1) 
    .forEach(...); 

Reverse сам список (и создать копию, если вы не может изменить оригинал)

List<String> reversed = new ArrayList(list); 
Collections.reverse(reversed); 
reversed.stream() 
    .forEach(...) 
+0

Это только что скопировано из http://stackoverflow.com/questions/24010109/java-8-stream-reverse-order, а не то, что OP действительно ищет – Andremoniy

+0

@Andremoniy Ну мне кажется, что OP хочет пересечь список в обратном порядке с использованием потоков. Связанный вопрос касается только обращения вспять IntStream, который фактически использует это для прохождения списка. –

+0

Нет, это немного измененная версия этой проблемы. Я бы закрыл этот вопрос – Andremoniy

3

есть объяснение, почему descendingIterator отсутствует в списке?

Эффективность итерации списка в значительной степени зависит от реализации этого списка.
При разработке интерфейса вы обычно хотите, чтобы интерфейс был подходящим для любых возможных вариантов его реализации.

Связанный с Java список является связанным списком, что означает, что каждый элемент связан с элементом, предшествующим и последующим им, поэтому можно писать эффективные восходящие и нисходящие итераторы.

Если вы использовали связанный список отдельно, было бы ужасно неэффективно сбрасывать его итерацию, вам нужно было бы пройти весь список до текущего индекса для каждой итерации.

Я подозреваю, что именно по этой причине разработчики языка решили опустить нисходящий итератор из интерфейса List.

Эффективный спуск на итератор ArrayList может быть реализован довольно легко с использованием подхода, основанного на индексе, использование индексного подхода в LinkedList будет намного медленнее, чем его предпочтительная реализация.

Некоторых примеры нисходящей итерационные подходы:

for(int i=list.size() -1; i >= 0; i--){ 
    System.out.println(list.get(i)); 
} 

IntStream.range(0, list.size()) 
     .map(i-> list.size() - 1 - i) 
     .mapToObj(list::get) 
     .forEach(System.out::println); 
4

Там нет действительно хорошей причины, почему List не может иметь нисходящий итератор. Каждый List необходим для поддержки ListIterator, который может быть повторен в обратном порядке с использованием методов и previous(). Это, кажется, довольно необычный случай использования.

Вот небольшой вспомогательный метод, который адаптирует Iterable к ListIterator итерации в обратном порядке:

static <T> Iterable<T> descendingIterable(List<? extends T> list) { 
    return() -> { 
     ListIterator<? extends T> li = list.listIterator(list.size()); 
     return new Iterator<T>() { 
      public boolean hasNext() { return li.hasPrevious(); } 
      public T next() { return li.previous(); } 
     }; 
    }; 
} 

Вы можете использовать его, чтобы реализовать свой пример:

List<String> list = Arrays.asList("Hello", "2", "Chocolate", "10"); 
    StringJoiner sj = new StringJoiner(" "); 
    descendingIterable(list).iterator().forEachRemaining(sj::add); 
    System.out.println(sj); 

    10 Chocolate 2 Hello 

Или вы могли бы использовать его в усиленная петля:

for (String s : descendingIterable(list)) { 
     System.out.println(s); 
    } 

    10 
    Chocolate 
    2 
    Hello 

Первоначально если бы это создало Iterator вместо Iterable, но последнее более полезно, поскольку оно может использоваться в цикле расширенного цикла.

Обратите внимание, что здесь есть небольшая морщина, которая заключается в том, что существует условие гонки, если List может быть одновременно изменено. Это происходит в коде здесь:

 list.listIterator(list.size()) 

Если это возможно, вы должны либо использовать внешнюю синхронизацию в списке, или если список является CopyOnWriteArrayList, вы должны клонировать его первым. См. this answer для получения дополнительной информации о последнем.

 Смежные вопросы

  • Нет связанных вопросов^_^