コレクションをリストに変換する方法は?


294

ApacheコレクションライブラリTreeBidiMapから使用しています。これを次の値で並べ替えます。doubles

私の方法は、以下を使用しCollectionて値のを取得することです:

Collection coll = themap.values();

これは自然にうまくいきます。

主な質問:次に、どのように変換/キャストして(どちらが正しいかわからない)collListソートできるようにしたいのですが?

次に、並べ替えられたListオブジェクトを反復処理します。これは順序どおりであり、イテレータがのリストで使用される場所を使用してTreeBidiMapthemap)から適切なキーを取得します。themap.getKey(iterator.next())doubles


4
ある種のSortedMapを直接使用してこの手順を回避し、エントリが使用されているキーの自然な順序になるようにすることができます。Java独自のTreeMapはSortedMapを実装しています。
アクセルクナウフ

TreeBidiMapは、OrderedMap順序は問題ないはずです。質問で必要な並べ替えは、キーではなく値に基づいています。
Vlasec、2015年

回答:


470
List list = new ArrayList(coll);
Collections.sort(list);

Erel Segal Haleviが以下に述べるように、collが既にリストである場合は、ステップ1をスキップできます。しかし、それはTreeBidiMapの内部に依存します。

List list;
if (coll instanceof List)
  list = (List)coll;
else
  list = new ArrayList(coll);

4
2つの方法には異なる副作用があることに注意してください。コレクションをリストにキャストしてから並べ替えると、元のコレクションも並べ替えられます。コピーを作成することはできません。
Barney、

この方法を繰り返し使用すると、パフォーマンスが大幅に低下します。オンザフライで機能するソリューションについては私の回答を参照してください。カスタムコレクションが含まれます。
Vlasec

これは、map.values()が「内部クラス」コレクションを返す場合を解決しません。コンパイラーは、Collections.sort(List <T>)がCollections.sort(List <InnerClass>)を受け入れないことを報告します。解決策はさらに使用することでした:List <InnerClass> list = map.values()。stream()。collect(Collectors.toList())
Pereira


33

新しいリストを作成してすべての要素をコピーするので、collが既にリストである場合、Paul Tomblinの答えは無駄かもしれません。collに多くの要素が含まれている場合、これには時間がかかることがあります。

私の提案は:

List list;
if (coll instanceof List)
  list = (List)coll;
else
  list = new ArrayList(coll);
Collections.sort(list);

21

私はそれをそのように書くことができると信じています:

coll.stream().collect(Collectors.toList())

キャストを回避するためのより良い方法
Stackee007

すごい!これは私のケースを解決しました。私のmap.values()は「内部クラス」コレクションを返します。コンパイラーは、Collections.sort(List <T>)がCollections.sort(List <InnerClass>)を受け入れないことを報告しました。
ペレイラ

私のアンドロイドのユースケースではうまくいきませんでした。最小API 24が必要
ansh sachdeva

8
Collections.sort( new ArrayList( coll ) );

ArrayListにアクセスするための参照がありませんか?
Zach Scrivena 2009

@ザック:うーん良い点。これをCWとしてマークする理由があることは知っていました。ところで、Paulのansがその1つです。なぜ彼は私の紫外線しか持っていないのか分かりません。
OscarRyz、2009

4

@国頭:グアバのnewArrayList方法を間違えていると思います。Iterableがリスト型であるかどうかはチェックせず、指定されたリストをそのまま返します。それは常に新しいリストを作成します:

@GwtCompatible(serializable = true)
public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
  checkNotNull(elements); // for GWT
  // Let ArrayList's sizing logic work, if possible
  return (elements instanceof Collection)
      ? new ArrayList<E>(Collections2.cast(elements))
      : newArrayList(elements.iterator());
}

どうしてこれ以上賛成投票されないのですか?国頭氏の答えは正しくありません(それが基礎となる実装について想定している限り)。
GreenieMeanie 2014

0

要求するのは非常にコストのかかる操作です。頻繁に(たとえば、サイクルで)実行する必要がないことを確認してください。

それ以外の場合は、カスタムコレクションを作成できます。私はあなたTreeBidiMapTreeMultisetフードの下にあるものを思いつきました。必要なものだけを実装し、データの整合性を考慮します。

class MyCustomCollection implements Map<K, V> {
    TreeBidiMap<K, V> map;
    TreeMultiset<V> multiset;
    public V put(K key, V value) {
        removeValue(map.put(key, value));
        multiset.add(value);
    }
    public boolean remove(K key) {
        removeValue(map.remove(key));
    }
    /** removes value that was removed/replaced in map */
    private removeValue(V value) {
        if (value != null) {
            multiset.remove(value);
        }
    }
    public Set keySet() {
        return map.keySet();
    }
    public Multiset values() {
        return multiset;
    }
    // many more methods to be implemented, e.g. count, isEmpty etc.
}

このようにして、から返されるソートされたもの Multisetが得られvalues()ます。ただし、リストにする必要がある場合(たとえば、配列のようなget(index)メソッドが必要な場合)は、より複雑なものを発明する必要があります。


keySet()およびvalues()は元のビューなMapので、それらが変更された場合、バッキングも変更するMap必要があります。ソリューションはこれをサポートしていません
Lino

-4

以下は、ワンライナーとしての最適ではないソリューションです。

Collections.list(Collections.enumeration(coll));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.