代码之家  ›  专栏  ›  技术社区  ›  Allain Lalonde

在Java中以相反顺序迭代列表

  •  227
  • Allain Lalonde  · 技术社区  · 15 年前

    我正在迁移一段代码以利用泛型。这样做的一个参数是for循环比跟踪索引或使用显式迭代器要干净得多。

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

    有人能建议一个更干净的方法来做这件事吗(因为我不喜欢 indexed for loop 在处理集合时),尽管它确实有效?

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

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

    15 回复  |  直到 6 年前
        1
  •  416
  •   John Feminella    15 年前

    试试这个:

    // 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());
    }
    
        2
  •  32
  •   Iulian Popescu John B    7 年前

    Guava 提供 Lists#reverse(List) ImmutableList#reverse() . 在大多数情况下,对于瓜娃来说,如果争论是 ImmutableList ,所以您可以在所有情况下使用前者。这些不会创建列表的新副本,只会创建列表的“反向视图”。

    例子

    List reversed = ImmutableList.copyOf(myList).reverse();
    
        3
  •  21
  •   Adamski    15 年前

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

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

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

        4
  •  14
  •   rogerdpack    9 年前

    选项1:你有没有想过用 Collections#reverse() 然后用前臂?

    当然,您也可能希望重构代码,使列表的顺序正确,这样您就不必反转它了,因为这会占用额外的空间/时间。


    编辑:

    选项2:或者,您可以使用 Deque 而不是数组列表?它允许您向前和向后迭代


    编辑:

    选项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);
    }
    
        5
  •  9
  •   sth    14 年前

    你可以用混凝土课 LinkedList 而不是通用接口 List . 然后你有一个 descendingIterator 用于反向迭代。

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

    不知道为什么没有 下降振荡器 具有 ArrayList

        6
  •  7
  •   fps    6 年前

    这是一个古老的问题,但缺少一个java8友好的答案。以下是使用流式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
    
        7
  •  5
  •   Tobb    9 年前

    如果列表相当小,因此性能不是真正的问题,则可以使用 reverse -元 Lists 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]
    

    也就是说,mylist的反向迭代可以写成:

    for (final String someString : Lists.reverse(myList)) {
        //do something
    }
    
        8
  •  5
  •   Paulo Mattos    6 年前

    创建自定义 reverseIterable .

        9
  •  4
  •   Adamski    15 年前

    下面是一个(未测试的)实现 ReverseIterable . 什么时候? iterator() 它创建并返回一个私有 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()));
      }
    }
    
        10
  •  3
  •   Bo Persson Touseef    12 年前

    非常简单的例子:

    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) {
      ...
    }
    
        11
  •  2
  •   Allain Lalonde    15 年前

    还发现了谷歌收藏 reverse 方法。

        13
  •  2
  •   Aubin    10 年前

    要获得类似这样的代码:

    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();
                    }
                };
            }
        }
    }
    
        14
  •  0
  •   masterxilo    10 年前

    如建议至少两次,您可以使用 descendingIterator 用一个 Deque ,尤其是 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);
            }
        }
    }
    
        15
  •  -9
  •   Thiem Nguyen    12 年前

    理由:“不知道为什么没有带数组列表的降序迭词…”

    因为数组列表并没有保持列表与添加到列表中的数据的顺序相同。所以,不要使用数组列表。

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

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