如何在Java中的列表上获得反向列表视图?


214

我想在列表上有一个反向列表视图(以与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


1
您可以从相反的顺序开始构建列表吗?
托尼·恩尼斯

是的,它确实可以-java.uitl.List.listIterator(int)download.oracle.com/javase/6/docs/api/java/util / ...
TofuBeer 2010年

如果您访问此链接找到如何反向(修改)列表的答案,则答案是:Collections.reverse(list)
ZhaoGang

Answers:


209

番石榴提供此功能: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,这纯粹是一个视图 ...它不会改变原始列表中元素的顺序。此外,使用可修改的原始列表,对原始列表和视图的更改都会反映在另一个列表中。


11
问题在于番石榴是一个非常大的图书馆。查看讨论内容:github.com/google/guava/issues/1954code.google.com/p/guava-libraries/issues/detail?id=605
Filipe Brito

2
@Filipe de Lima Brito:ProGuard仍然是库大小的最佳解决方案,尽管我们可以做出一些改进。无论如何,我都不认为库大小与该答案有任何关系。
ColinD

2
是的,库的大小与这个答案无关,但是与程序员了解有关(因此,我评论了)!非常感谢您提供的出色库和@ColinD的建议!
Filipe Brito 2015年

@ColinD,是的,这是我的错误。一位同事添加了google-collection,它们也具有相同的名称空间和class(List),但没有反向方法。删除它使番石榴再次可用。
AaA

开发人员并不总是能够控制自己可以使用哪些库,而为如此简单的事情添加一个全新的库似乎有点过头了-尤其是考虑到问题可以通过以下方式解决ListIterator.previous()
Jonathan Benn

218

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

嗯,

Collections.reverse(list.clone());

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

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

21
clone()通常会创建列表的副本。反正List#clone()也不存在。
艾伯特

6
从技术上来说,您是正确的,List接口本身不提供clone()方法。但是ArrayList,LinkedList和Vector都可以。
jcalvert 2010年

2
我只是查询了的实现clone()。实际上,它确实完成了列表的完整副本(它仅不克隆列表中的每个对象,而这绝不是我所说的)。
艾伯特

21
请注意,Collections.reverse返回void,因此您将丢失克隆引用。您需要先将克隆分配给变量,然后对其进行排序。
user12722

10
subList不复制,它仅提供基础列表的视图,因此反转该视图将反转基础列表。
罗兰


35

它并不十分优雅,但是如果您使用List.listIterator(int index),则可以在列表的末尾获得双向ListIterator:

//Assume List<String> foo;
ListIterator li = foo.listIterator(foo.size());

while (li.hasPrevious()) {
   String curr = li.previous()
}

1
这是最好的答案,因为(1)它不需要库,并且(2)它不需要按照OP的要求修改原始列表
Jonathan Benn

12

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


8
您只是在重复别人6年前写的答案
Jonathan Benn

1
...而不是视图。这会使列表发生变化。
詹森·S

6

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


如果您不想使用内置的descndingIterator()方法,似乎最好使用ConcurrentLinkedDeque来逆转很大的列表?基本上只是使用民意调查从一个卡座复制到新卡座然后提供?Sorta就像只是拥有一副纸牌,然后将每张纸牌从顶部移到新的纸堆中一样。
djangofan '17

4

我知道这是一篇旧文章,但今天我正在寻找这样的东西。最后,我自己编写了代码:

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个元素)。

希望它能帮助到别人。


2
您的代码有一个问题-您可以在其中添加任何List,但它始终会返回ArrayList(作为List)。如果我需要LinkedList怎么办?最好修改myList并返回void。
德米特里·扎伊采夫2012年

2
请注意,这并不是我真正想要的。我要的是某种代理/视图,而不是副本。
艾伯特

4

我用这个:

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

1

您也可以这样做:

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

5
那不是列表视图。视图与副本相反。
艾伯特

空列表的反向列表为null?
ShellFish

1

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

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

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

-3

使用类的reverse(...)方法java.util.Collections。将列表作为参数传递,列表将被反转。

Collections.reverse(list);

1
现有答案的副本
Karl Richter
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.