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


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

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

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

есть ли способ повторить список строк в обратном порядке с помощью для каждого синтаксис?

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

12 133

12 ответов:

не используйте коллекции.обратный метод он фактически отменяет исходный список на месте. Если вы используете его:

неправильный путь!

Collections.reverse(new ArrayList(stringList))

чтобы избежать изменения оригинала, это возвращает новый список с элементами исходного списка, скопированными в него в обратном порядке, и такой имеет 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);
}

для списка, вы можете использовать Библиотека Google Guava:

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

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

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

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

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

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

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

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

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

Collections.reverse(stringList);

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

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

вы могли бы сделать что-то вроде for(Item element: myList.клон.)(обратный ()) и оплатить соответствующую цену.

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

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

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

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

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

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

как @rogerdpack сказал, вам необходимо заключить в ReverseListIterator как Iterable.

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

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

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

вы можете использовать класс коллекцийhttp://java.sun.com/j2se/1.4.2/docs/api/java/util/Collections.html чтобы изменить список, то цикл.

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

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

вот решение скопировано с мышление в Java 4-е издание глава 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
*///:~

определенно поздний ответ на этот вопрос. Одна возможность-использовать 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"