[英]Can one do a for each loop in java in reverse order?
我需要使用 Java 以相反的順序運行 List。
那么它在哪里轉發:
for(String string: stringList){
//...do something
}
有什么方法可以使用for each語法以相反的順序迭代 stringList 嗎?
為清楚起見:我知道如何以相反的順序迭代列表,但想知道(出於好奇)如何在每種樣式中執行此操作。
Collections.reverse 方法實際上返回一個新列表,其中原始列表的元素以相反的順序復制到其中,因此相對於原始列表的大小,它的性能為 O(n)。
作為更有效的解決方案,您可以編寫一個裝飾器,將 List 的反向視圖顯示為 Iterable。 裝飾器返回的迭代器將使用裝飾列表的 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 Library :
for (String item : Lists.reverse(stringList))
{
// ...
}
請注意, Lists.reverse
不會反轉整個集合,也不會執行類似的操作 - 它只允許以相反的順序進行迭代和隨機訪問。 這比首先反轉集合更有效。
要反轉任意可迭代對象,您必須閱讀所有內容,然后向后“重播”它。
(如果你還沒有使用它,我會全力推薦你看看番石榴。這是偉大的東西。)
List(與 Set 不同)是一個有序集合,迭代它確實按合同保留了順序。 我本來希望 Stack 以相反的順序迭代,但不幸的是它沒有。 所以我能想到的最簡單的解決方案是:
for (int i = stack.size() - 1; i >= 0; i--) {
System.out.println(stack.get(i));
}
我意識到這不是“for each”循環解決方案。 我寧願使用 for 循環而不是引入像 Google Collections 這樣的新庫。
Collections.reverse() 也可以完成這項工作,但它會更新列表,而不是以相反的順序返回副本。
這將與原始列表混淆,並且還需要在循環外調用。 此外,您不想在每次循環時都執行反向操作 - 如果應用了Iterables.reverse ideas
之一,那會是真的嗎?
Collections.reverse(stringList);
for(String string: stringList){
//...do something
}
AFAIK 標准庫中沒有標准的“reverse_iterator”類型的東西支持 for-each 語法,這已經是他們后期引入語言的語法糖。
您可以執行類似 for(Item element: myList.clone().reverse()) 的操作並支付相關價格。
這似乎也與沒有為您提供方便的方法來執行昂貴操作的明顯現象相當一致 - 因為根據定義,列表可能具有 O(N) 隨機訪問復雜度(您可以使用單鏈接實現接口),反向迭代最終可能是 O(N^2)。 當然,如果你有一個 ArrayList,你就不用付出那個代價。
截至評論:您應該能夠使用 Apache Commons ReverseListIterator
Iterable<String> reverse
= new IteratorIterable(new ReverseListIterator(stringList));
for(String string: reverse ){
//...do something
}
正如@rogerdpack 所說,您需要將ReverseListIterator
包裝為Iterable
。
正如Roland Nordborg-Løvstad 在評論中所推薦的,您可以使用當前 Java 中的 Lambdas 進行簡化
Iterable<String> reverse = () -> new ReverseListIterator<>(stringList)
這可能是一種選擇。 希望有更好的方法從最后一個元素開始而不是 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);
}
}
並非沒有編寫一些自定義代碼,這些代碼將為您提供一個枚舉器,它將為您反轉元素。
您應該能夠通過創建 Iterable 的自定義實現來在 Java 中執行此操作,該實現將以相反的順序返回元素。
然后,您將實例化包裝器(或調用方法,what-have-you),它將返回 Iterable 實現,該實現反轉 for each 循環中的元素。
您可以使用Collections類來反轉列表然后循環。
如果您想開箱即用地使用 for each 語法並以相反的順序進行,則需要反轉您的集合。
以上所有答案都只滿足要求,要么包裝另一種方法,要么在外面調用一些外部代碼;
這里是從Thinking in Java 4th edition , 章節 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
*///:~
一個工作:
Collections.reverse(stringList).forEach(str -> ...);
或者用番石榴:
Lists.reverse(stringList).forEach(str -> ...);
絕對是這個問題的遲到答案。 一種可能性是在 for 循環中使用 ListIterator。 它不像冒號語法那么干凈,但它有效。
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 中迭代列表的方法”
例如
Integer[][] a = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 9, 8, 9 },
};
List<List<Integer>> arr = Arrays.stream(a)
.map(Arrays::asList)
.collect(Collectors.toList());
現在反轉。
Collections.reverse(arr);
System.out.println("Reverse Array" + arr);
for (List<Integer> obj : arr) {
// TODO
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.