在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(); } }; } } }
你可以使用Apache Commons-Collections的ReverseListIterator
:
至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) { ... }