Можно ли сделать каждый цикл в java в обратном порядке?

Мне нужно запустить List в обратном порядке с помощью Java.

Итак, где это делается вперед:

for(String string: stringList){
//...do something
}

Есть ли способ перебрать stringList в обратном порядке, используя для каждого синтаксиса?

Для ясности: я знаю, как перебирать список в обратном порядке, но хотел бы знать (ради любопытства), как это сделать для каждого стиля.

Ответ 1

Метод Collections.reverse фактически возвращает новый список с элементами оригинального списка, скопированными в него в обратном порядке, поэтому он имеет производительность O (n) относительно размера исходного списка.

Как более эффективное решение, вы могли бы написать декоратор, который представляет перевернутое представление списка как итерируемого. Итератор, возвращаемый вашим декоратором, будет использовать ListIterator оформленного списка для обхода элементов в обратном порядке.

Например:

public class Reversed<T> implements Iterable<T> {
    private final List<T> original;

    public Reversed(List<T> original) {
        this.original = original;
    }

    public Iterator<T> iterator() {
        final ListIterator<T> i = original.listIterator(original.size());

        return new Iterator<T>() {
            public boolean hasNext() { return i.hasPrevious(); }
            public T next() { return i.previous(); }
            public void remove() { i.remove(); }
        };
    }

    public static <T> Reversed<T> reversed(List<T> original) {
        return new Reversed<T>(original);
    }
}

И вы бы использовали это как:

import static Reversed.reversed;

...

List<String> someStrings = getSomeStrings();
for (String s : reversed(someStrings)) {
    doSomethingWith(s);
}

Ответ 2

Для списка вы можете использовать Google Guava Library:

for (String item : Lists.reverse(stringList))
{
    // ...
}

Обратите внимание, что Lists.reverse не отменяет всю коллекцию или не делает ничего подобного - она ​​просто разрешает итерацию и произвольный доступ, в в обратном порядке. Это более эффективно, чем обратная сборка.

Чтобы отменить произвольное итерируемое, вам нужно будет все прочитать, а затем "воспроизвести" его назад.

(Если вы еще не используете его, я настоятельно рекомендую вам взглянуть на Guava..)

Ответ 3

Список (в отличие от Set) представляет собой упорядоченную коллекцию и итерацию по ней сохраняет заказ по контракту. Я бы ожидал, что Stack будет итератировать в обратном порядке, но, к сожалению, это не так. Поэтому самое простое решение, о котором я могу думать, следующее:

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

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

Collections.reverse() также выполняет задание, но он обновляет список, а не возвращает копию в обратном порядке.

Ответ 4

Это будет бесполезно с исходным списком и также должно быть вызвано вне цикла. Также вы не хотите выполнять обратное при каждом цикле - было бы верно, если был применен один из Iterables.reverse ideas?

Collections.reverse(stringList);

for(String string: stringList){
//...do something
}

Ответ 5

AFAIK в стандартной библиотеке не существует стандартного типа "reverse_iterator", который поддерживает синтаксис for-each, который уже является синтаксическим сахаром, который они заподозрили на языке.

Вы можете сделать что-то вроде (элемент Item: myList.clone(). reverse()) и оплатить соответствующую цену.

Это также кажется вполне согласующимся с очевидным явлением, которое не дает вам удобных способов выполнения дорогостоящих операций - поскольку список по определению может иметь сложность произвольного доступа O (N) (вы можете реализовать интерфейс с помощью однострочной), обратная итерация может оказаться O (N ^ 2). Конечно, если у вас есть ArrayList, вы не платите эту цену.

Ответ 6

Это может быть вариант. Надеюсь, есть лучший способ начать с последнего элемента, чем до цикла while.

public static void main(String[] args) {        
    List<String> a = new ArrayList<String>();
    a.add("1");a.add("2");a.add("3");a.add("4");a.add("5");

    ListIterator<String> aIter=a.listIterator();        
    while(aIter.hasNext()) aIter.next();

    for (;aIter.hasPrevious();)
    {
        String aVal = aIter.previous();
        System.out.println(aVal);           
    }
}

Ответ 7

Как комментарий: вы должны иметь возможность использовать Apache Commons ReverseListIterator

Iterable<String> reverse 
    = new IteratorIterable(new ReverseListIterator(stringList));

for(String string: reverse ){
    //...do something
}

Как @rogerdpack сказал, вам нужно обернуть ReverseListIterator как Iterable.

Ответ 8

Не забудьте написать какой-то пользовательский код, который даст вам перечислитель, который изменит вам элементы.

Вы должны иметь возможность сделать это на Java, создав пользовательскую реализацию Iterable, которая вернет элементы в обратном порядке.

Затем вы создадите экземпляр обертки (или вызовите метод, what-have-you), который вернет реализацию Iterable, которая меняет элемент в каждом цикле.

Ответ 10

Вам нужно будет отменить свою коллекцию, если вы хотите использовать для каждого синтаксиса из коробки и идти в обратном порядке.

Ответ 11

Все вышеприведенные ответы удовлетворяют только требованию, либо путем переноса другого метода, либо внешнего кода внешнего кода;

Вот решение, скопированное из четвертого издания "Мышление в Java", глава 11.13.1 AdapterMethodIdiom;

Вот код:

// The "Adapter Method" idiom allows you to use foreach
// with additional kinds of Iterables.
package holding;
import java.util.*;

@SuppressWarnings("serial")
class ReversibleArrayList<T> extends ArrayList<T> {
  public ReversibleArrayList(Collection<T> c) { super(c); }
  public Iterable<T> reversed() {
    return new Iterable<T>() {
      public Iterator<T> iterator() {
        return new Iterator<T>() {
          int current = size() - 1; //why this.size() or super.size() wrong?
          public boolean hasNext() { return current > -1; }
          public T next() { return get(current--); }
          public void remove() { // Not implemented
            throw new UnsupportedOperationException();
          }
        };
      }
    };
  }
}   

public class AdapterMethodIdiom {
  public static void main(String[] args) {
    ReversibleArrayList<String> ral =
      new ReversibleArrayList<String>(
        Arrays.asList("To be or not to be".split(" ")));
    // Grabs the ordinary iterator via iterator():
    for(String s : ral)
      System.out.print(s + " ");
    System.out.println();
    // Hand it the Iterable of your choice
    for(String s : ral.reversed())
      System.out.print(s + " ");
  }
} /* Output:
To be or not to be
be to not or be To
*///:~

Ответ 12

Определенно поздний ответ на этот вопрос. Одной из возможностей является использование ListIterator в цикле for. Это не так чисто, как синтаксис двоеточия, но это работает.

List<String> exampleList = new ArrayList<>();
exampleList.add("One");
exampleList.add("Two");
exampleList.add("Three");

//Forward iteration
for (String currentString : exampleList) {
    System.out.println(currentString); 
}

//Reverse iteration
for (ListIterator<String> itr = exampleList.listIterator(exampleList.size()); itr.hasPrevious(); /*no-op*/ ) {
    String currentString = itr.previous();
    System.out.println(currentString); 
}

Кредит для синтаксиса ListIterator идет в "Способы перебора списка в Java"

Ответ 13

Работа вокруг:

Collections.reverse(stringList).forEach(str -> ...);

Или с гуавой:

Lists.reverse(stringList).forEach(str -> ...);