在java中以相反顺序遍历列表

我正在迁移一段代码以利用generics。 这样做的一个参数是for循环比跟踪索引或使用显式迭代器更清洁。

在大约一半的情况下,列表(一个ArrayList)正在通过使用今天的索引以相反的顺序迭代。

有人可以build议一个更清洁的方式做到这一点(因为我不喜欢indexed for loop处理集合),虽然它的工作?

  for (int i = nodes.size() - 1; i >= 0; i--) { final Node each = (Node) nodes.get(i); ... } 

注意:我不能在JDK之外添加任何新的依赖关系。

尝试这个:

 // Substitute appropriate type. ArrayList<...> a = new ArrayList<...>(); // Add elements to list. // Generate an iterator. Start just after the last element. ListIterator li = a.listIterator(a.size()); // Iterate in reverse. while(li.hasPrevious()) { System.out.println(li.previous()); } 

番石榴提供Lists#reverse(List)ImmutableList#reverse() 。 和大多数番石榴一样,如果参数是一个ImmutableList ,则前者委托给后者,所以在所有情况下都可以使用前者。 这些不会创build列表的新副本,但只是“颠倒了”它的观点。

 List reversed = ImmutableList.copyOf(myList).reverse(); 

我不认为使用for循环语法是可能的。 我能build议的唯一的事情就是做一些事情:

 Collections.reverse(list); for (Object o : list) { ... } 

…但我不会说这是“干净”的,因为它效率会降低。

select1:你有没有想过使用集合#reverse()然后使用foreach颠倒列表?

当然,你也可能想重构你的代码,使得列表被正确sorting,所以你不必倒过来,这会占用额外的空间/时间。


编辑:

选项2:或者,您可以使用Deque而不是ArrayList? 它将允许你迭代前后颠倒


编辑:

选项3:正如其他人所build议的那样,您可以编写一个迭代器,它将以相反的顺序遍历列表,这里是一个例子:

 import java.util.Iterator; import java.util.List; public class ReverseIterator<T> implements Iterator<T>, Iterable<T> { private final List<T> list; private int position; public ReverseIterator(List<T> list) { this.list = list; this.position = list.size() - 1; } @Override public Iterator<T> iterator() { return this; } @Override public boolean hasNext() { return position >= 0; } @Override public T next() { return list.get(position--); } @Override public void remove() { throw new UnsupportedOperationException(); } } List<String> list = new ArrayList<String>(); list.add("A"); list.add("B"); list.add("C"); list.add("D"); list.add("E"); for (String s : new ReverseIterator<String>(list)) { System.out.println(s); } 

创build一个自定义的reverseIterable

你可以使用具体的类LinkedList来代替一般的接口List 。 然后你有一个descendingIterator迭代器,用于反向迭代。

 LinkedList<String > linkedList; for( Iterator<String > it = linkedList.descendingIterator(); it.hasNext(); ) { String text = it.next(); } 

不知道为什么没有ArrayList descendingIterator ArrayList

这是一个ReverseIterable的(未经testing的)实现。 当调用iterator() ,它将创build并返回一个专用的ReverseIterator实现,该实现仅将hasNext()调用映射到hasPrevious()并将next()调用映射到previous() 。 这意味着你可以按如下方式反过来遍历一个ArrayList

 ArrayList<String> l = ... for (String s : new ReverseIterable(l)) { System.err.println(s); } 

类定义

 public class ReverseIterable<T> implements Iterable<T> { private static class ReverseIterator<T> implements Iterator { private final ListIterator<T> it; public boolean hasNext() { return it.hasPrevious(); } public T next() { return it.previous(); } public void remove() { it.remove(); } } private final ArrayList<T> l; public ReverseIterable(ArrayList<T> l) { this.l = l; } public Iterator<T> iterator() { return new ReverseIterator(l.listIterator(l.size())); } } 

如果列表非常小,以至于性能不是真正的问题,那么可以使用Google Guava中的Lists class的reverse代码。 for-each代码的产量相当for-each ,原始列表保持不变。 而且,反向列表由原始列表支持,所以对原始列表的任何改变都将反映在反向列表中。

 import com.google.common.collect.Lists; [...] final List<String> myList = Lists.newArrayList("one", "two", "three"); final List<String> myReverseList = Lists.reverse(myList); System.out.println(myList); System.out.println(myReverseList); myList.add("four"); System.out.println(myList); System.out.println(myReverseList); 

产生以下结果:

 [one, two, three] [three, two, one] [one, two, three, four] [four, three, two, one] 

这意味着myList的反向迭代可以写成:

 for (final String someString : Lists.reverse(myList)) { //do something } 

非常简单例如:

 List<String> list = new ArrayList<String>(); list.add("ravi"); list.add("kant"); list.add("soni"); // Iterate to disply : result will be as --- ravi kant soni for (String name : list) { ... } //Now call this method Collections.reverse(list); // iterate and print index wise : result will be as --- soni kant ravi for (String name : list) { ... } 

这是一个古老的问题,但它缺乏一个java8友好的答案。 以下是在Streaming API的帮助下反向迭代列表的一些方法:

 List<Integer> list = new ArrayList<Integer>(Arrays.asList(1, 3, 3, 7, 5)); list.stream().forEach(System.out::println); // 1 3 3 7 5 ListIterator<Integer> it = list.listIterator(list.size()); Stream.generate(() -> it.previous()).limit(list.size()) .forEach(System.out::println); // 5 7 3 3 1 ListIterator<Integer> it2 = list.listIterator(list.size()); Stream.iterate(it2.previous(), i -> it2.previous()).limit(list.size()) .forEach(System.out::println); // 5 7 3 3 1 // If list is RandomAccess (ie an ArrayList) IntStream.range(0, list.size()).map(i -> list.size() - i - 1).map(list::get) .forEach(System.out::println); // 5 7 3 3 1 // If list is RandomAccess (ie an ArrayList) IntStream.range(0, list.size()).boxed().sorted(Comparator.reverseOrder()) .map(list::get).forEach(System.out::println); // 5 7 3 3 1 

还发现谷歌收集反向的方法。

要使代码看起来像这样:

 List<Item> items; ... for (Item item : In.reverse(items)) { ... } 

将这段代码放入一个名为“In.java”的文件中:

 import java.util.*; public enum In {; public static final <T> Iterable<T> reverse(final List<T> list) { return new ListReverseIterable<T>(list); } class ListReverseIterable<T> implements Iterable<T> { private final List<T> mList; public ListReverseIterable(final List<T> list) { mList = list; } public Iterator<T> iterator() { return new Iterator<T>() { final ListIterator<T> it = mList.listIterator(mList.size()); public boolean hasNext() { return it.hasPrevious(); } public T next() { return it.previous(); } public void remove() { it.remove(); } }; } } } 

至less有两次build议,可以使用Deque descendingIterator ,特别是LinkedList 。 如果你想使用for-each循环(即有一个Iterable ),你可以像这样构造和使用一个包装器:

 import java.util.*; public class Main { public static class ReverseIterating<T> implements Iterable<T> { private final LinkedList<T> list; public ReverseIterating(LinkedList<T> list) { this.list = list; } @Override public Iterator<T> iterator() { return list.descendingIterator(); } } public static void main(String... args) { LinkedList<String> list = new LinkedList<String>(); list.add("A"); list.add("B"); list.add("C"); list.add("D"); list.add("E"); for (String s : new ReverseIterating<String>(list)) { System.out.println(s); } } } 

原因:“不知道为什么ArrayList没有降序的迭代器…”

由于数组列表不会保持列表中的数据已添加到列表的顺序。 所以,不要使用Arraylist。

链接列表将保持数据以相同的顺序添加列表。

所以,在上面的例子中,我使用ArrayList()来使用户扭曲他们的头脑,并使他们从他们身边锻炼。

而不是这个

 List<String> list = new ArrayList<String>(); 

使用:

 List<String> list = new LinkedList<String>(); list.add("ravi"); list.add("kant"); list.add("soni"); // Iterate to disply : result will be as --- ravi kant soni for (String name : list) { ... } //Now call this method Collections.reverse(list); // iterate and print index wise : result will be as --- soni kant ravi for (String name : list) { ... }