webentwicklung-frage-antwort-db.com.de

Kann man für jede Schleife in Java in umgekehrter Reihenfolge vorgehen?

Ich muss eine Liste mit Java in umgekehrter Reihenfolge durchlaufen. 

Wo also geht es weiter:

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

Gibt es eine Möglichkeit, die stringList in umgekehrter Reihenfolge mit der für jede -Syntax zu durchlaufen?

Der Klarheit halber: Ich kann eine Liste in umgekehrter Reihenfolge durchlaufen, möchte aber (um der Neugierde willen) wissen, wie sie im für jeden - Stil geht.

134
Ron Tuffin

Die Collections.reverse-Methode gibt tatsächlich eine neue Liste mit den Elementen der ursprünglichen Liste zurück, die in umgekehrter Reihenfolge in die Liste kopiert wurden. Dies hat also eine Leistung von O(n) in Bezug auf die Größe der ursprünglichen Liste.

Als effizientere Lösung können Sie einen Dekorator schreiben, der eine umgekehrte Ansicht einer Liste als Iterable darstellt. Der von Ihrem Dekorateur zurückgegebene Iterator verwendet den ListIterator der dekorierten Liste, um die Elemente in umgekehrter Reihenfolge zu durchlaufen.

Zum Beispiel:

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

Und du würdest es so benutzen:

import static Reversed.reversed;

...

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

Für eine Liste können Sie die Google Guava Library verwenden:

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

Beachten Sie, dass Lists.reversenicht die gesamte Auflistung rückgängig macht oder ähnliche Schritte unternimmt - es ermöglicht lediglich Iteration und wahlfreien Zugriff in umgekehrter Reihenfolge. Dies ist effizienter, als die Sammlung zuerst rückgängig zu machen.

Um ein beliebiges iterierbares Element umzukehren, müssen Sie es alle lesen und es rückwärts "wiedergeben".

(Wenn Sie es nicht bereits verwenden, würde ich gründlich empfehlen, dass Sie sich die Guava ansehen. Es ist tolles Zeug.)

91
Jon Skeet

Die Liste (im Gegensatz zum Set) ist eine geordnete Sammlung, und die Iteration darüber bewahrt die Bestellung vertraglich. Ich hätte erwartet, dass ein Stack in umgekehrter Reihenfolge durchlaufen würde, aber leider nicht. Die einfachste Lösung, die mir einfällt, ist folgende:

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

Mir ist klar, dass dies keine "für jede" Schleifenlösung ist. Ich würde lieber die for-Schleife verwenden, als eine neue Bibliothek wie die Google Collections einzuführen.

Collections.reverse () führt ebenfalls den Job aus, aktualisiert jedoch die Liste, anstatt eine Kopie in umgekehrter Reihenfolge zurückzugeben.

34
Gopi Reddy

Dies führt zu einer Störung der ursprünglichen Liste und muss auch außerhalb der Schleife aufgerufen werden .. Sie möchten auch nicht jedes Mal eine Umkehrung durchführen, wenn dies der Fall wäre, wenn einer der Iterables.reverse ideas wäre angewendet?

Collections.reverse(stringList);

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

AFAIK: In der Standardbibliothek gibt es keine Standardfunktion für "reverse_iterator", die die for-each-Syntax unterstützt, die bereits einen syntaktischen Zucker enthält, den sie erst spät in die Sprache eingebracht haben. 

Sie könnten etwas für (Elementelement: myList.clone (). Reverse ()) machen und den zugehörigen Preis bezahlen. 

Dies scheint auch ziemlich im Einklang mit dem offensichtlichen Phänomen zu stehen, dass Sie keine bequemen Möglichkeiten für teure Operationen erhalten - da eine Liste per Definition O(N) - Random-Access-Komplexität haben könnte (Sie könnten die Schnittstelle mit einer einzigen Schnittstelle implementieren) link), könnte die umgekehrte Iteration O (N ^ 2) sein. Wenn Sie eine ArrayList haben, zahlen Sie diesen Preis natürlich nicht. 

4
Uri

Dies kann eine Option sein. Ich hoffe, es gibt einen besseren Weg, um vom letzten Element zu starten, als bis zum Ende der Schleife.

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

Ab dem Kommentar : Sie sollten Apache Commons ReverseListIterator verwenden können.

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

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

Wie in @rogerdpack angegeben, müssen Sie die ReverseListIterator als Iterable umschließen. 

2
serv-inc

Nicht ohne einen benutzerdefinierten Code zu schreiben, der einen Enumerator enthält, der die Elemente für Sie umkehrt.

Sie sollten dies in Java tun können, indem Sie eine benutzerdefinierte Implementierung von Iterable erstellen, die die Elemente in umgekehrter Reihenfolge zurückgibt.

Dann würden Sie den Wrapper instanziieren (oder die Methode "What-Have-You") aufrufen, die die Iterable-Implementierung zurückgibt, die das Element in der jeweiligen Schleife umkehrt.

1
casperOne

Sie können die Collections-Klasse http://Java.Sun.com/j2se/1.4.2/docs/api/Java/util/Collections.html verwenden, um die Liste umzudrehen und die Schleife zu wiederholen.

1
Allan

Sie müssen Ihre Sammlung stornieren, wenn Sie die Syntax für jede Syntax verwenden und in umgekehrter Reihenfolge verwenden möchten.

1
Owen

Alle obigen Antworten erfüllen die Anforderung nur, indem sie entweder eine andere Methode verwenden oder Fremdcode aufrufen.

Hier ist die Lösung aus der Thinking in Java 4th Edition , Kapitel 11.13.1 AdapterMethodIdiom ;

Hier ist der Code:

// 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
*///:~
1
qiwen li

Auf jeden Fall eine späte Antwort auf diese Frage. Eine Möglichkeit besteht darin, den ListIterator in einer for-Schleife zu verwenden. Es ist nicht so sauber wie die Doppelpunkt-Syntax, aber es funktioniert.

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

Die ListIterator-Syntax geht an "Möglichkeiten, eine Liste in Java zu durchlaufen"

0
ScottMichaud