简体   繁体   English

可以以相反的顺序为java中的每个循环做一个吗?

[英]Can one do a for each loop in java in reverse order?

I need to run through a List in reverse order using Java.我需要使用 Java 以相反的顺序运行 List。

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 each语法以相反的顺序迭代 stringList 吗?

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.为清楚起见:我知道如何以相反的顺序迭代列表,但想知道(出于好奇)如何在每种样式中执行此操作。

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. Collections.reverse 方法实际上返回一个新列表,其中原始列表的元素以相反的顺序复制到其中,因此相对于原始列表的大小,它的性能为 O(n)。

As a more efficient solution, you could write a decorator that presents a reversed view of a List as an Iterable.作为更有效的解决方案,您可以编写一个装饰器,将 List 的反向视图显示为 Iterable。 The iterator returned by your decorator would use the ListIterator of the decorated list to walk over the elements in reverse order.装饰器返回的迭代器将使用装饰列表的 ListIterator 以相反的顺序遍历元素。

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

For a list, you could use the Google Guava Library :对于列表,您可以使用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.请注意, Lists.reverse不会反转整个集合,也不会执行类似的操作 - 它只允许以相反的顺序进行迭代和随机访问。 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.) (如果你还没有使用它,我会全力推荐你看看番石榴。这是伟大的东西。)

The List (unlike the Set) is an ordered collection and iterating over it does preserve the order by contract. List(与 Set 不同)是一个有序集合,迭代它确实按合同保留了顺序。 I would have expected a Stack to iterate in the reverse order but unfortunately it doesn't.我本来希望 Stack 以相反的顺序迭代,但不幸的是它没有。 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.我意识到这不是“for each”循环解决方案。 I'd rather use the for loop than introducing a new library like the Google Collections.我宁愿使用 for 循环而不是引入像 Google Collections 这样的新库。

Collections.reverse() also does the job but it updates the list as opposed to returning a copy in reverse order. Collections.reverse() 也可以完成这项工作,但它会更新列表,而不是以相反的顺序返回副本。

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?此外,您不想在每次循环时都执行反向操作 - 如果应用了Iterables.reverse ideas之一,那会是真的吗?

Collections.reverse(stringList);

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

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. AFAIK 标准库中没有标准的“reverse_iterator”类型的东西支持 for-each 语法,这已经是他们后期引入语言的语法糖。

You could do something like for(Item element: myList.clone().reverse()) and pay the associated price.您可以执行类似 for(Item element: myList.clone().reverse()) 的操作并支付相关价格。

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).这似乎也与没有为您提供方便的方法来执行昂贵操作的明显现象相当一致 - 因为根据定义,列表可能具有 O(N) 随机访问复杂度(您可以使用单链接实现接口),反向迭代最终可能是 O(N^2)。 Of course, if you have an ArrayList, you don't pay that price.当然,如果你有一个 ArrayList,你就不用付出那个代价。

As of the comment : You should be able to use Apache Commons ReverseListIterator截至评论:您应该能够使用 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 .正如@rogerdpack 所说,您需要将ReverseListIterator包装为Iterable

As recommended by Roland Nordborg-Løvstad in the comments , you can simplify with Lambdas in current Java正如Roland Nordborg-Løvstad 在评论中推荐的,您可以使用当前 Java 中的 Lambdas 进行简化

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

This may be an option.这可能是一种选择。 Hope there is a better way to start from last element than to while loop to the end.希望有更好的方法从最后一个元素开始而不是 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);           
    }
}

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.您应该能够通过创建 Iterable 的自定义实现来在 Java 中执行此操作,该实现将以相反的顺序返回元素。

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

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

如果您想开箱即用地使用 for each 语法并以相反的顺序进行,则需要反转您的集合。

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 ;这里是从Thinking in Java 4th edition , 章节 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
*///:~

A work Around :一个工作:

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

Or with guava :或者用番石榴

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

Definitely a late answer to this question.绝对是这个问题的迟到答案。 One possibility is to use the ListIterator in a for loop.一种可能性是在 for 循环中使用 ListIterator。 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" ListIterator 语法归功于“在 Java 中迭代列表的方法”

Eg例如

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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM