我们可以在 java 中以相反的顺序做一个 for 循环吗?

我需要使用 Java 以相反的顺序运行 List。

那么它会转发到哪里:

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

有没有什么方法可以使用 每个人语法以相反的顺序迭代 stringList?

为了清晰起见: 我知道如何以相反的顺序迭代一个列表,但是我想知道(出于好奇心)如何以 每个人的方式迭代。

150053 次浏览

AFAIK 在标准库中没有标准的“反向迭代器”之类的东西来支持 for-each 语法,而 for-each 语法已经是他们在语言后期引入的一种语法糖。

您可以执行类似于 for (Item 元素: myList.clone () . return ())的操作并支付相关的价格。

这似乎也与不给你方便的方法去做昂贵的操作的明显现象相一致——因为一个列表,根据定义,可能有 O (N)随机访问复杂性(你可以用一个单链接实现接口) ,反向迭代可能最终是 O (N ^ 2)。当然,如果你有一个数组列表,你不会付出这样的代价。

不写一些自定义代码,这将给你一个枚举器,这将为您反转元素。

通过创建 Iterable 的自定义实现,您应该能够在 Java 中实现这一点,该实现将以相反的顺序返回元素。

然后,您将实例化包装器(或调用方法 what-have-you) ,它将返回 Iterable 实现,该实现将反转 for 循环中的元素。

您可以使用 收款类来反转列表,然后循环。

如果您希望使用 for 每种语法并按照相反的顺序执行,则需要反向收集。

对于一个列表,您可以使用 谷歌番石榴图书馆:

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

请注意,Lists.reverse 没有反转整个集合,或者做任何类似的事情-它只是允许迭代和随机访问,以相反的顺序。这比首先反转集合更有效。

要逆转一个任意的迭代,您必须全部读取它,然后向后“重播”它。

(如果你还没有使用它,我建议你看一下 番石榴。这是很棒的东西。)

Return 方法实际上返回一个新列表,其中原始列表的元素按照相反的顺序复制到该列表中,因此对于原始列表的大小,该方法具有 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);
}

这将与原始列表混淆,并且还需要在循环外调用。 而且你也不想每次循环时都执行反向操作——如果应用了 Iterables.reverse ideas的其中一个,这样的操作是否正确?

Collections.reverse(stringList);


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

这也许是个选择。希望有一个更好的方法从最后一个元素开始,而不是循环到结束。

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

List (与 Set 不同)是一个有序的集合,并且通过对它的迭代确实保留了契约的顺序。我希望 Stack 以相反的顺序进行迭代,但不幸的是它没有。所以我能想到的最简单的解决办法是:

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

我意识到这不是一个“针对每个人”的循环解决方案。我更愿意使用 for 循环,而不是引入类似 Google Collection 这样的新库。

Re ()也执行这项工作,但是它更新列表,而不是以相反的顺序返回副本。

评论开始: 您应该能够使用 ApacheCommons 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)

以上所有答案都只能满足需求,或者包装另一个方法,或者在外部调用一些外部代码;

下面是从 Java 第四版的思考第11.13.1章 适配器方法习语复制的解决方案;

密码如下:

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

这个问题回答得太迟了。一种可能性是在 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 中迭代列表的方法”

返回文章页面解决方案:

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

或与 番石榴合作:

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

例如。

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
}