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.
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);
}
Für eine Liste können Sie die Google Guava Library verwenden:
for (String item : Lists.reverse(stringList))
{
// ...
}
Beachten Sie, dass Lists.reverse
nicht 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.)
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.
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
}
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.
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);
}
}
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.
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.
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.
Sie müssen Ihre Sammlung stornieren, wenn Sie die Syntax für jede Syntax verwenden und in umgekehrter Reihenfolge verwenden möchten.
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
*///:~
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"