2009-07-08 36 views
122

我需要使用Java以相反顺序遍历List。可以按照相反的顺序对java中的每个循环执行一次吗?

那么,这确实是前锋:

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

有没有一些方法来遍历的StringList以相反的顺序使用每个语法?

为清楚:我知道如何遍历以相反的顺序列表,但想知道(出于好奇的缘故)如何做到这一点的每个风格。

+3

有趣的是,我中途读斯卡拉书与不可变列表操作交易...在缺乏表现力的一个很好的示范部分读出这个问题java的。 – skaffman 2009-07-08 13:37:49

+5

“for-each”循环的要点是您只需要对每个元素执行操作,而顺序并不重要。因为每个人都可以按照完全随机的顺序处理元素,而且它仍然会按照设计的目的进行。如果您需要以特定方式处理元素,我会建议您手动进行。 – muusbolla 2009-07-08 13:46:19

+0

Java集合库。与语言无关。怪乔希布洛赫。 – 2009-07-08 13:50:59

回答

129

不要使用Collections.reverse方法实际上颠倒了原始列表已到位。如果使用它:

错误的方式!

Collections.reverse(new ArrayList(stringList))

以避免修改原来,这返回与复制到它以相反的顺序原始列表的元素的新的列表,并且这样的为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); 
} 
4

AFAIK在标准库中没有标准的“reverse_iterator”类标准库,它支持for-each语法,它已经是一种语法延迟的语法糖。

你可以做类似于(Item元素:myList.clone()。reverse())并支付相关的价格。

这似乎与不给你方便的昂贵操作方式的表面现象相当一致 - 因为根据定义,列表可能具有O(N)随机访问的复杂性(您可以使用单向函数实现接口)链接),反向迭代最终可能是O(N^2)。当然,如果你有一个ArrayList,你不会支付这个价格。

+0

您可以向后运行一个ListIterator,它可以在Iterator中包装。 – 2009-07-08 13:52:18

+0

@Tom:好点。但是,使用迭代器,您仍然在做烦人的旧式for循环,并且您仍然可能需要花费才能开始使用最后一个元素......不过,我在回答中添加了限定符,谢谢。 – Uri 2009-07-08 14:01:33

1

不是没有编写一些自定义代码,它会给你一个枚举器,它将为你反转元素。

您应该可以通过创建Iterable的自定义实现来完成它,它将以相反的顺序返回元素。然后,你将实例化包装器(或者调用方法,what-have-you),它将返回Iterable实现,该实现会颠倒每个循环中的元素。

1

如果您想要使用每种语法的开箱即用方式,您需要将您的收藏反转。

84

有关列表,你可以使用Google Guava Library

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

注意Lists.reverse扭转整个集合,或做那样的事情 - 它只是允许重复和随机存取,在相反的顺序。这比先倒收集效率更高。

要反转一个任意的迭代,你必须全部读完,然后“重放”它。

(如果你还没有使用它,我彻底建议你看看Guava。这是伟大的东西。)

8

这会搞乱与原来的列表,还需要在循环外部调用。 你也不想在每次循环时执行反向操作 - 如果应用了Iterables.reverse ideas之一,那么这是真的吗?

Collections.reverse(stringList); 

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

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

列表(与集合不同)是一个有序集合,迭代它可以保持订单的合同。我会希望堆栈以相反的顺序迭代,但不幸的是它没有。所以我能想到的最简单的解决方案是:

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

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

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

1

由于the comment:你应该能够使用Apache下议院ReverseListIterator

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

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

由于@rogerdpack said,你需要用的ReverseListIteratorIterable

0

以上所有答案只能满足要求,可以通过包装另一种方法或在外面调用某些外部代码;

下面是用Java第四版的思维复制的解决方案,章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 
*///:~ 
相关问题