【问题标题】:How to get a reversed list view on a list in Java?如何在 Java 中的列表上获得反向列表视图?
【发布时间】:2011-04-27 03:21:54
【问题描述】:

我想在列表上有一个反向列表视图(类似于List#sublist 在列表上提供子列表视图)。有没有提供这个功能的函数?

我不想复制列表,也不想修改列表。

在这种情况下,如果我能在列表中至少获得一个反向迭代器就足够了。


另外,我知道如何自己实现这一点。我只是问Java是否已经提供了类似的东西。

演示实现:

static <T> Iterable<T> iterableReverseList(final List<T> l) {
    return new Iterable<T>() {
        public Iterator<T> iterator() {
            return new Iterator<T>() {
                ListIterator<T> listIter = l.listIterator(l.size());                    
                public boolean hasNext() { return listIter.hasPrevious(); }
                public T next() { return listIter.previous(); }
                public void remove() { listIter.remove(); }                 
            };
        }
    };
}

我刚刚发现一些List 实现具有descendingIterator(),这正是我所需要的。尽管List 没有这样的通用实现。这有点奇怪,因为我在LinkedList 中看到的实现足够通用,可以与任何List 一起使用。

【问题讨论】:

  • 你能以相反的顺序构建列表吗?
  • 是的 - java.uitl.List.listIterator(int) download.oracle.com/javase/6/docs/api/java/util/…
  • 如果您访问此链接以找到如何反转(修改)列表的答案,这就是答案:Collections.reverse(list)

标签: java list collections iterator reverse


【解决方案1】:

对于小型列表,我们可以创建LinkedList,然后可以使用降序迭代器:

List<String> stringList = new ArrayList<>(Arrays.asList("One", "Two", "Three"));
stringList.stream().collect(Collectors.toCollection(LinkedList::new))
         .descendingIterator().
         forEachRemaining(System.out::println); // Three, Two, One
System.out.println(stringList); // One, Two, Three

【讨论】:

    【解决方案2】:

    Collections.reverse(nums) ...它实际上颠倒了元素的顺序。 下面的代码应该非常感谢 -

    List<Integer> nums = new ArrayList<Integer>();
    nums.add(61);
    nums.add(42);
    nums.add(83);
    nums.add(94);
    nums.add(15);
    //Tosort the collections uncomment the below line
    //Collections.sort(nums); 
    
    Collections.reverse(nums);
    
    System.out.println(nums);
    

    输出:15,94,83,42,61

    【讨论】:

    • 你只是在重复别人6年前写的答案
    • ...而不是视图。这会改变列表。
    【解决方案3】:

    您还可以在请求对象时反转位置:

    Object obj = list.get(list.size() - 1 - position);
    

    【讨论】:

      【解决方案4】:

      Guava 提供:Lists.reverse(List)

      List<String> letters = ImmutableList.of("a", "b", "c");
      List<String> reverseView = Lists.reverse(letters); 
      System.out.println(reverseView); // [c, b, a]
      

      Collections.reverse 不同,这纯粹是一个视图...它不会改变原始列表中元素的顺序。此外,对于可修改的原始列表,对原始列表和视图的更改都会反映在另一个中。

      【讨论】:

      • 问题是 Guava 是一个非常大的库。查看讨论:github.com/google/guava/issues/1954code.google.com/p/guava-libraries/issues/detail?id=605
      • @Filipe de Lima Brito:ProGuard 仍然是库大小的最佳解决方案,尽管我们可以做出改进。无论如何,我认为图书馆的大小与这个答案没有任何关系。
      • 是的,库大小与此答案无关,但与通知程序员有关(因此,我评论了)!非常感谢您对这个伟大的图书馆和@ColinD 的建议!
      • @ColinD,是的,这是我的错误。一位同事添加了 google-collections,它们也具有相同的命名空间和类 (List),但没有反向方法。删除它使番石榴再次可用。
      • 开发人员并不总是能够控制他们可以使用哪些库,为如此简单的事情添加一个全新的库似乎有点过分——尤其是考虑到问题可以通过ListIterator.previous() 解决/跨度>
      【解决方案5】:

      在您的列表中使用 .clone() 方法。它将返回一个浅拷贝,这意味着它将包含指向相同对象的指针,因此您不必复制列表。然后只需使用集合。

      所以,

      Collections.reverse(list.clone());
      

      如果您使用的是List,但无权访问clone(),您可以使用subList()

      List<?> shallowCopy = list.subList(0, list.size());
      Collections.reverse(shallowCopy);
      

      【讨论】:

      • clone() 通常会创建列表的副本。反正List#clone()也不存在。
      • 您在技术上是正确的,List 接口本身不提供 clone() 方法。但是 ArrayList、LinkedList 和 Vector 都可以。
      • 我刚刚查了clone()的实现。它确实做了列表的完整副本(它只是不克隆列表中的每个对象,但这从来不是我在说的)。
      • 请注意,Collections.reverse 返回 void,因此您将丢失克隆引用。您需要先将克隆分配给变量,然后对其进行排序。
      • subList 不复制,它只是提供底层列表的视图,因此反转此视图将反转底层列表。
      【解决方案6】:

      我用这个:

      public class ReversedView<E> extends AbstractList<E>{
      
          public static <E> List<E> of(List<E> list) {
              return new ReversedView<>(list);
          }
      
          private final List<E> backingList;
      
          private ReversedView(List<E> backingList){
              this.backingList = backingList;
          }
      
          @Override
          public E get(int i) {
              return backingList.get(backingList.size()-i-1);
          }
      
          @Override
          public int size() {
              return backingList.size();
          }
      
      }
      

      像这样:

      ReversedView.of(backingList) // is a fully-fledged generic (but read-only) list
      

      【讨论】:

        【解决方案7】:

        如果我理解正确,那就是一行代码。它对我有用。

         Collections.reverse(yourList);
        

        【讨论】:

        • 这不是列表视图。这会修改列表。
        【解决方案8】:

        你也可以这样做:

        static ArrayList<String> reverseReturn(ArrayList<String> alist)
        {
           if(alist==null || alist.isEmpty())
           { 
               return null;
           }
        
           ArrayList<String> rlist = new ArrayList<>(alist);
        
           Collections.reverse(rlist);
           return rlist;
        }
        

        【讨论】:

        • 这不是列表视图。视图与副本相反。
        • 空列表的反向列表为空??
        【解决方案9】:

        我知道这是一篇旧帖子,但今天我正在寻找类似的东西。最后我自己写了代码:

        private List reverseList(List myList) {
            List invertedList = new ArrayList();
            for (int i = myList.size() - 1; i >= 0; i--) {
                invertedList.add(myList.get(i));
            }
            return invertedList;
        }
        

        不推荐用于长列表,这根本没有优化。对于受控场景来说,这是一种简单的解决方案(我处理的列表不超过 100 个元素)。

        希望它对某人有所帮助。

        【讨论】:

        • 您的代码有一个问题 - 您可以将任何 List 放入其中,但它总是会返回 ArrayList(作为 List)。如果我需要 LinkedList 怎么办?最好修改myList,返回void。
        • 请注意,这并不是我真正想要的。我要的是某种代理/视图,而不是副本。
        【解决方案10】:

        java.util.Deque 具有 descendingIterator() - 如果您的 ListDeque,您可以使用它。

        【讨论】:

        • 如果您不想使用内置的 descdingIterator() 方法,似乎使用 ConcurrentLinkedDeque 将是反转非常大的列表的最佳选择?基本上只是使用 poll 从一个牌组复制到新牌组然后提供?有点像一副纸牌,然后按顺序从顶部取出每张纸牌。
        【解决方案11】:

        它不是很优雅,但是如果你使用 List.listIterator(int index) 你可以得到一个双向 ListIterator 到列表的末尾:

        //Assume List<String> foo;
        ListIterator li = foo.listIterator(foo.size());
        
        while (li.hasPrevious()) {
           String curr = li.previous()
        }
        

        【讨论】:

        • 这是最好的答案,因为 (1) 它不需要库,并且 (2) 它不会按照 OP 的要求修改原始列表
        猜你喜欢
        • 1970-01-01
        • 2016-02-01
        • 2018-09-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多