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
最初に逆の順序でリストを作成できますか?
Tony Ennis、

java.uitl.List.listIterator(INT) -はいそれはありませんdownload.oracle.com/javase/6/docs/api/java/util/...
TofuBeer

あなたは(変更)リストを逆にどのような答えを見つけるために、このリンクを訪問した場合、これが答えです:Collections.reverse(list)
ZhaoGang

回答:


209

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、これは純粋にビューです。元のリストの要素の順序は変更されません。さらに、変更可能な元のリストを使用すると、元のリストとビューの両方への変更が他方に反映されます。


11
問題は、グアバが非常に大きなライブラリであることです。次のディスカッションをご覧ください:github.com/google/guava/issues/1954およびcode.google.com/p/guava-libraries/issues/detail?id=605
Filipe Brito

2
@Filipe de Lima Brito:ライブラリーサイズの最適なソリューションはProGuardです。いずれにせよ、ライブラリのサイズがこの回答に何らかの意味で関連しているとは思いません。
ColinD

2
はい、ライブラリのサイズはこの回答には関係ありませんが、プログラマーに通知するために関係があります(したがって、私はコメントしました)。この素晴らしいライブラリとあなたの提案@ColinDをありがとう!
Filipe Brito

@ColinD、うん、それは私の間違いだった。同僚は、同じ名前空間とクラス(List)を持っているが逆のメソッドがないgoogle-collectionsを追加しました。それを削除すると、グアバが再び利用可能になります。
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

2
の実装を調べたところですclone()。実際、リストの完全なコピーを作成します(リスト内の各オブジェクトを複製するだけではありませんが、それは私が話していたことではありませんでした)。
アルバート

21
Collections.reverseはvoidを返すため、クローン参照が失われることに注意してください。最初にクローンを変数に割り当て、次にそれをソートする必要があります。
user12722

10
subListコピーせず、単に基になるリストのビューを提供するだけなので、このビューを逆にすると、基になるリストが逆になります。
Roland

80

私が正しいことを理解していれば、それはコードの1行です。それは私のために働きました。

 Collections.reverse(yourList);

12
これはリストビューではありません。リストが変更されます。
アルバート

35

正確ではありませんが、List.listIterator(int index)を使用すると、リストの最後まで双方向のListIteratorを取得できます。

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

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

1
OPが要求したように、(1)ライブラリを必要とせず、(2)元のリストを変更しないため、これが最良の答えです
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
...ビューではありません。これはリストを変更します。
Jason S

6

java.util.Deque持っているdescendingIterator()-あなたListがであればDeque、それを使うことができます。


組み込みのdescndingIterator()メソッドを使用したくない場合は、ConcurrentLinkedDequeを使用するのが非常に大きなリストを元に戻すのに最適だと思われますか?基本的に、pollを使用して1つのデッキから新しいデッキにコピーしてから、オファーしますか?カードのデッキを用意し、それぞれをトップから新しいパイルに順番に並べ替えるようなものです。
djangofan 2017

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
あなたのコードには1つの問題があります-あなたはそれに任意のリストを置くことができますが、それは常にあなたに(リストとして)ArrayListを返します。また、LinkedListが必要な場合はどうなりますか?myListを変更してvoidを返すことをお勧めします。
Dmitry Zaytsev 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 2017年

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
既存の回答のコピー
カールリヒター
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.