java中的foreach循环可以逆序执行吗?

发布于 2024-07-25 23:47:33 字数 260 浏览 4 评论 0原文

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

那么它转发到哪里:

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

是否有某种方法可以使用 foreach 语法以相反的顺序迭代 stringList?

为了清楚起见:我知道如何以相反的顺序迭代列表,但想知道(出于好奇)如何以 foreach 样式执行此操作。

I need to run through a List in reverse order using Java.

So where this does it forwards:

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

Is there some way to iterate the stringList in reverse order using the for each syntax?

For clarity: I know how to iterate a list in reverse order but would like to know (for curiosity's sake ) how to do it in the for each style.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(16

生活了然无味 2024-08-01 23:47:33

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

The Collections.reverse method actually returns a new list with the elements of the original list copied into it in reverse order, so this has O(n) performance with regards to the size of the original list.

As a more efficient solution, you could write a decorator that presents a reversed view of a List as an Iterable. The iterator returned by your decorator would use the ListIterator of the decorated list to walk over the elements in reverse order.

For example:

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

And you would use it like:

import static Reversed.reversed;

...

List<String> someStrings = getSomeStrings();
for (String s : reversed(someStrings)) {
    doSomethingWith(s);
}
隔纱相望 2024-08-01 23:47:33

如需列表,您可以使用 Google Guava Library

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

请注意 Lists.reverse 不会反转整个集合,或者做类似的事情 - 它只允许以相反的顺序进行迭代和随机访问。 这比先逆向收集效率更高。

要反转任意可迭代对象,您必须读取全部内容,然后向后“重播”它。

(如果您尚未使用它,我强烈建议您查看番石榴。这是很棒的东西。)

For a list, you could use the Google Guava Library:

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

Note that Lists.reverse doesn't reverse the whole collection, or do anything like it - it just allows iteration and random access, in the reverse order. This is more efficient than reversing the collection first.

To reverse an arbitrary iterable, you'd have to read it all and then "replay" it backwards.

(If you're not already using it, I'd thoroughly recommend you have a look at the Guava. It's great stuff.)

半窗疏影 2024-08-01 23:47:33

List(与 Set 不同)是一个有序集合,对其进行迭代确实会按约定保留顺序。 我本来期望堆栈以相反的顺序迭代,但不幸的是它没有。 所以我能想到的最简单的解决方案是:

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

我意识到这不是“foreach”循环解决方案。 我宁愿使用 for 循环,也不愿引入像 Google Collections 这样的新库。

Collections.reverse() 也可以完成这项工作,但它会更新列表,而不是以相反的顺序返回副本。

The List (unlike the Set) is an ordered collection and iterating over it does preserve the order by contract. I would have expected a Stack to iterate in the reverse order but unfortunately it doesn't. So the simplest solution I can think of is this:

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

I realize that this is not a "for each" loop solution. I'd rather use the for loop than introducing a new library like the Google Collections.

Collections.reverse() also does the job but it updates the list as opposed to returning a copy in reverse order.

横笛休吹塞上声 2024-08-01 23:47:33

这会扰乱原始列表,并且还需要在循环之外调用。
另外,您不想每次循环时都执行反向操作 - 如果应用了 Iterables.reverse 想法 之一,情况会是这样吗?

Collections.reverse(stringList);

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

This will mess with the original list and also needs to be called outside of the loop.
Also you don't want to perform a reverse every time you loop - would that be true if one of the Iterables.reverse ideas was applied?

Collections.reverse(stringList);

for(String string: stringList){
//...do something
}
满天都是小星星 2024-08-01 23:47:33

AFAIK 标准库中没有标准的“reverse_iterator”之类的东西支持 for-each 语法,这已经是他们后期引入该语言的语法糖。

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

这似乎也与不为您提供执行昂贵操作的便捷方法的明显现象相当一致 - 因为根据定义,列表可能具有 O(N) 随机访问复杂度(您可以使用单链接实现接口),相反迭代最终可能是 O(N^2)。 当然,如果你有一个ArrayList,你就不需要付出这个代价。

AFAIK there isn't a standard "reverse_iterator" sort of thing in the standard library that supports the for-each syntax which is already a syntactic sugar they brought late into the language.

You could do something like for(Item element: myList.clone().reverse()) and pay the associated price.

This also seems fairly consistent with the apparent phenomenon of not giving you convenient ways to do expensive operations - since a list, by definition, could have O(N) random access complexity (you could implement the interface with a single-link), reverse iteration could end up being O(N^2). Of course, if you have an ArrayList, you don't pay that price.

不弃不离 2024-08-01 23:47:33

截至评论:您应该能够使用 Apache Commons ReverseListIterator

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

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

作为 @rogerdpack 说,您需要将 ReverseListIterator 包装为 可迭代

作为 Roland Nordborg-Løvstad 在评论中推荐,您可以在当前的 Java 中使用 Lambdas 进行简化

Iterable<String> reverse = () -> new ReverseListIterator<>(stringList)

As of the comment: You should be able to use Apache Commons ReverseListIterator

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

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

As @rogerdpack said, you need to wrap the ReverseListIterator as an Iterable.

As recommended by Roland Nordborg-Løvstad in the comments, you can simplify with Lambdas in current Java

Iterable<String> reverse = () -> new ReverseListIterator<>(stringList)
蓝色星空 2024-08-01 23:47:33

这可能是一个选择。 希望有一种更好的方法从最后一个元素开始而不是 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);           
    }
}

This may be an option. Hope there is a better way to start from last element than to while loop to the end.

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);           
    }
}
白况 2024-08-01 23:47:33

解决方法:

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

或者使用 guava

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

A work Around :

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

Or with guava :

Lists.reverse(stringList).forEach(str -> ...);
烟沫凡尘 2024-08-01 23:47:33

从 Java 21 开始,reversed() 方法可用于返回列表上的反向视图,然后可以使用增强的 for 对其进行迭代陈述:

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

Starting with Java 21, the reversed() method can be used to return a reversed view on the list, which can then be iterated over using an enhanced for statement:

for (String string : stringList.reversed()) {
    //...do something
}
预谋 2024-08-01 23:47:33

并非没有编写一些自定义代码,这将为您提供一个枚举器,该枚举器将为您反转元素。

您应该能够在 Java 中通过创建 Iterable 的自定义实现来完成此操作,该实现将以相反的顺序返回元素。

然后,您将实例化包装器(或调用方法,您有什么),它将返回 Iterable 实现,该实现反转 foreach 循环中的元素。

Not without writing some custom code which will give you an enumerator which will reverse the elements for you.

You should be able to do it in Java by creating a custom implementation of Iterable which will return the elements in reverse order.

Then, you would instantiate the wrapper (or call the method, what-have-you) which would return the Iterable implementation which reverses the element in the for each loop.

心碎的声音 2024-08-01 23:47:33

如果您想使用开箱即用的 foreach 语法并按相反的顺序进行操作,则需要反转集合。

You'd need to reverse your collection if you want to use the for each syntax out of the box and go in reverse order.

卖梦商人 2024-08-01 23:47:33

上面的所有答案都只能满足要求,要么通过包装另一个方法,要么在外部调用一些外部代码;

以下是从 Thinking in 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
*///:~

All answers above only fulfill the requirement, either by wrapping another method or calling some foreign code outside;

Here is the solution copied from the Thinking in Java 4th edition, chapter 11.13.1 AdapterMethodIdiom;

Here is the 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
*///:~
尘世孤行 2024-08-01 23:47:33

您可以使用 Collections 类反转列表然后循环。

You can use the Collections class to reverse the list then loop.

醉梦枕江山 2024-08-01 23:47:33

绝对是这个问题的迟到答案。 一种可能性是在 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 中迭代列表的方法”

Definitely a late answer to this question. One possibility is to use the ListIterator in a for loop. It's not as clean as colon-syntax, but it works.

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

Credit for the ListIterator syntax goes to "Ways to iterate over a list in Java"

断桥再见 2024-08-01 23:47:33

例如,

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
}

E.g.

Integer[][] a = {
                { 1, 2, 3 }, 
                { 4, 5, 6 }, 
                { 9, 8, 9 }, 
                };

List<List<Integer>> arr = Arrays.stream(a)
                .map(Arrays::asList)
                .collect(Collectors.toList());

Reverse it now.

Collections.reverse(arr);
System.out.println("Reverse Array" + arr);
for (List<Integer> obj : arr) {
    // TODO
}
冬天的雪花 2024-08-01 23:47:33

您可以使用 For-Each 循环以相反的顺序迭代数组,如下所示:

public class Main {
    public static void main(String[] args) {
        int arr[] = {2,3,1,4,7,6};
        int i = arr.length-1;
        for(int e: arr){
            // do something
            System.out.print(arr[i] + "\t");
            i--;
        }
    }
}

You can iterate through an array in reverse order using For-Each loop like below:

public class Main {
    public static void main(String[] args) {
        int arr[] = {2,3,1,4,7,6};
        int i = arr.length-1;
        for(int e: arr){
            // do something
            System.out.print(arr[i] + "\t");
            i--;
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文