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

时间:2010-01-20 15:28:24

标签: java collections

我正在迁移一段代码以使用泛型。这样做的一个论点是for循环比跟踪索引或使用显式迭代器更清晰。

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

有人可以建议一种更简洁的方法吗(因为我在处理集合时不喜欢indexed for loop),虽然它确实有用吗?

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

注意:我无法在JDK之外添加任何新的依赖项。

16 个答案:

答案 0 :(得分:424)

试试这个:

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

答案 1 :(得分:32)

Guava提供Lists#reverse(List)ImmutableList#reverse()。与Guava的大多数情况一样,如果参数为ImmutableList,前者会委托后者,因此您可以在所有情况下使用前者。这些不会创建列表的新副本,而只是创建它的“反转视图”。

实施例

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

答案 2 :(得分:23)

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

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

...但我不会说这是“更清洁”,因为效率会降低。

答案 3 :(得分:14)

选项1:您是否考虑过使用Collections#reverse()撤消列表然后使用foreach?

当然,您可能还想重构代码,以便正确排序列表,这样您就不必反转它,这会占用额外的空间/时间。


编辑:

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


编辑:

选项3:正如其他人所建议的那样,你可以编写一个迭代通过列表的迭代器,这是一个例子:

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

答案 4 :(得分:9)

您可以使用具体类LinkedList而不是通用接口List。然后你有一个descendingIterator用于反向迭代。

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

不知道为什么没有descendingIterator ArrayList ...

答案 5 :(得分:8)

这是一个老问题,但它缺乏对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

int size = list.size();

ListIterator<Integer> it = list.listIterator(size);
Stream.generate(it::previous).limit(size)
    .forEach(System.out::println); // 5 7 3 3 1

ListIterator<Integer> it2 = list.listIterator(size);
Stream.iterate(it2.previous(), i -> it2.previous()).limit(size)
    .forEach(System.out::println); // 5 7 3 3 1

// If list is RandomAccess (i.e. an ArrayList)
IntStream.range(0, size).map(i -> size - i - 1).map(list::get)
    .forEach(System.out::println); // 5 7 3 3 1

// If list is RandomAccess (i.e. an ArrayList), less efficient due to sorting
IntStream.range(0, size).boxed().sorted(Comparator.reverseOrder())
    .map(list::get).forEach(System.out::println); // 5 7 3 3 1

答案 6 :(得分:6)

创建自定义reverseIterable

答案 7 :(得分:5)

如果列表相当小,以致性能不是真正的问题,可以使用reverseLists - Google Guava类的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]

产生以下结果:

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

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

{{1}}

答案 8 :(得分:4)

这是ReverseIterable的(未经测试的)实现。调用iterator()后,它会创建并返回一个私有ReverseIterator实现,该实现只会将对hasNext()的调用映射到hasPrevious(),并且对next()的调用将映射到{{ 1}}。这意味着您可以反向迭代previous(),如下所示:

ArrayList

课程定义

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

答案 9 :(得分:3)

非常简单示例:

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) {
  ...
}

答案 10 :(得分:2)

还找到了google collections reverse方法。

答案 11 :(得分:2)

要使代码看起来像这样:

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

答案 12 :(得分:2)

答案 13 :(得分:0)

至少有两次建议,您可以将descendingIteratorDeque一起使用,尤其是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);
        }
    }
}

答案 14 :(得分:0)

Valid for Java 9+

List<String> strList = List.of("a", "b", "c", "d", "e");

IntStream.iterate(strList.size() - 1, i -> i >= 0, i -> --i)
         .mapToObj(strList::get)
         .forEach(System.out::println);

答案 15 :(得分:-10)

原因:“不知道为什么没有带有ArrayList的descendingIterator ......”

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

链接列表将使数据保持与ADD相同的顺序列出。

所以,在我的例子中,我使用了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) {
  ...
}