web-dev-qa-db-ja.com

JavaにSortedListがないのはなぜですか?

JavaにはSortedSetSortedMapインターフェースがあります。どちらもJavaの標準のCollectionsフレームワークに属しており、要素にアクセスするためのソートされた方法を提供します。

しかし、私の理解では、JavaにはSortedListはありません。 Java.util.Collections.sort()を使ってリストをソートすることができます。

なぜそれがそのように設計されているのですか?

448
Jijoy

リスト反復子は、リストの内部順序でリストの要素を取得することを何よりもまず保証します(別名挿入順序)。具体的には、要素を挿入した順序、またはリストを操作した方法です。ソートはデータ構造の操作と見なすことができ、リストをソートするにはいくつかの方法があります。

個人的には有用性の順に方法を並べます。

1.代わりにSetまたはBagコレクションの使用を検討してください

注:これはとにかくやりたいことだから、このオプションを一番上に置いた。

並べ替えセットは、挿入時にコレクションを自動的に並べ替えます。つまり、コレクションに要素を追加するときに並べ替えを行います。また、手動で並べ替える必要がないことも意味します。

さらに、要素の重複を心配する必要がない(または持つ必要がある)場合は、代わりに TreeSet<T> を使用できます。 SortedSetおよびNavigableSetインターフェイスを実装し、おそらくリストから期待されるとおりに動作します。

TreeSet<String> set = new TreeSet<String>();
set.add("lol");
set.add("cat");
// automatically sorts natural order when adding

for (String s : set) {
    System.out.println(s);
}
// Prints out "cat" and "lol"

自然な順序が望ましくない場合は、 Comparator<T> を取るコンストラクターパラメーターを使用できます。

または、Multisets (別名Bags、それはSetであり、代わりに要素の重複を許可し、それらのサードパーティの実装があります。最も注目すべきは Guavaライブラリ から TreeMultiset があり、TreeSetと非常によく似ています。

2. Collections.sort()でリストをソートします

上記のように、Listsのソートは、データ構造の操作です。そのため、さまざまな方法でソートされる「真実の1つのソース」が必要な場合は、手動でソートするのが適切です。

Java.util.Collections.sort() メソッドでリストをソートできます。方法のサンプルコードを次に示します。

List<String> strings = new ArrayList<String>()
strings.add("lol");
strings.add("cat");

Collections.sort(strings);
for (String s : strings) {
    System.out.println(s);
}
// Prints out "cat" and "lol"

コンパレーターの使用

明らかな利点の1つは、Comparatorメソッドで sort を使用できることです。 Javaは、ロケール依存のソート文字列に役立つ Comparator などのCollatorの実装も提供します。次に例を示します。

Collator usCollator = Collator.getInstance(Locale.US);
usCollator.setStrength(Collator.PRIMARY); // ignores casing

Collections.sort(strings, usCollator);

並行環境でのソート

ただし、sortメソッドの使用は、コレクションインスタンスが操作されるため、同時環境では使いにくいため、代わりに不変コレクションの使用を検討する必要があることに注意してください。これは、Guavaが Ordering クラスで提供するものであり、単純な1行です。

List<string> sorted = Ordering.natural().sortedCopy(strings);

3.リストをJava.util.PriorityQueueでラップします

Javaにはソートされたリストはありませんが、ソートされたキューがありますが、おそらくあなたにとっても同様に機能します。 Java.util.PriorityQueue クラスです。

Nico Haaseはコメントで 関連する質問 にリンクしており、これも回答しています。

ソートされたコレクションでは、おそらく内部データ構造を操作したくないでしょうその要素に直接アクセスできます)。

PriorityQueueイテレータに関する注意

PriorityQueueクラスは、Iterable<E>およびCollection<E>インターフェイスを実装しているため、通常どおり反復できます。ただし、反復子は、ソートされた順序で要素を返すことは保証されていません。代わりに(Alderathがコメントで指摘しているように)空になるまでキューをpoll()する必要があります。

コレクションを取得するコンストラクタ を使用して、リストを優先度キューに変換できることに注意してください。

List<String> strings = new ArrayList<String>()
strings.add("lol");
strings.add("cat");

PriorityQueue<String> sortedStrings = new PriorityQueue(strings);
while(!sortedStrings.isEmpty()) {
    System.out.println(sortedStrings.poll());
}
// Prints out "cat" and "lol"

4.独自のSortedListクラスを書く

注:これを行う必要はありません。

新しい要素を追加するたびにソートする独自のListクラスを作成できます。これは、実装に応じてかなり重い計算になる可能性があり、無意味です。ただし、2つの主な理由から、演習として行う場合を除きます。

  1. addメソッドは、ユーザーが指定したインデックスに要素が存在することを保証する必要があるため、List<E>インターフェイスが持っている契約を破ります。
  2. なぜ車輪を再発明するのですか?上記の最初のポイントで指摘したように、代わりにTreeSetまたはMultisetsを使用する必要があります。

ただし、ここでの演習として開始したい場合のコードサンプルは、AbstractList抽象クラスを使用します。

public class SortedList<E> extends AbstractList<E> {

    private ArrayList<E> internalList = new ArrayList<E>();

    // Note that add(E e) in AbstractList is calling this one
    @Override 
    public void add(int position, E e) {
        internalList.add(e);
        Collections.sort(internalList, null);
    }

    @Override
    public E get(int i) {
        return internalList.get(i);
    }

    @Override
    public int size() {
        return internalList.size();
    }

}

必要なメソッドをオーバーライドしていない場合、AbstractListのデフォルトの実装はUnsupportedOperationExceptionsをスローします。

635
Spoike

リストの概念は自動的にソートされたコレクションの概念と互換性がないからです。 Listのポイントは、list.add(7, elem)を呼び出した後、list.get(7)を呼び出すとelemが返されることです。自動ソートリストでは、要素は任意の位置に配置される可能性があります。

61

すべてのリストは項目が追加された順(FIFO順)で既に「ソート」されているので、Java.util.Collections.sort()を使用して、要素の自然順を含む別の順序でそれらを「ソート」することができます。

編集:

データ構造としてのリストは、興味深いのは、項目が挿入された順序であることに基づいています。

集合はその情報を持っていません。

時間を追加して注文したい場合はListを使用してください。他の基準で並べ替えたい場合は、SortedSetを使用してください。

23
SJuan76

SetとMapは非線形データ構造です。リストは線形データ構造です。

enter image description here


ツリーデータ構造SortedSetSortedMapインターフェースはそれぞれused Red-Black tree 実装アルゴリズムを使ってTreeSetTreeMapを実装します。そのため、重複した項目(またはMapの場合はキー)がないことを確認します。

  • Listはすでに順序付きコレクションとインデックスベースのデータ構造を保持しています。ツリーはインデックスベースのデータ構造ではありません。
  • 定義上のTreeには重複を含めることはできません。
  • Listでは、重複する可能性があるので、TreeListはありません(つまり、SortedListはありません)。
  • リストは要素を挿入順に保持します。そのため、リストをソートしたい場合はJava.util.Collections.sort()を使用する必要があります。指定されたリストを、その要素の自然な順序に従って昇順に並べ替えます。
13
Premraj

2015年4月の時点で、Androidのサポートライブラリに SortedList クラスが追加されました。これはRecyclerViewで動作するように特別に設計されています。これが ブログ投稿 です。

9
Amagi82

JavaFX SortedList

時間はかかりましたが、Java 8にはソート済みのListがあります。 http://docs.Oracle.com/javase/8/javafx/api/javafx/collections/transformation/SortedList.html

Javadocにあるように、これは JavaFX コレクションの一部であり、ObservableListでソートされたビューを提供することを目的としています。

更新:Java 11では、JavaFXツールキットはJDKの外に移動し、現在は独立したライブラリになっています。 JavaFX 11は、ダウンロード可能なSDKとして、またはMavenCentralから入手できます。 https://openjfx.io を参照してください。

9
swpalmer

もう1つのポイントは、挿入操作の時間的な複雑さです。リスト挿入の場合、O(1)の複雑さが予想されます。しかし、これはソートされたリストでは保証できませんでした。

そして最も重要な点は、リストはそれらの要素について何も想定していないということです。たとえば、equalscompareを実装していないもののリストを作成できます。

4
Ingo

Listインターフェースには、add(int index, E element)set(int index, E element)などのメソッドがあります。契約では、一度位置Xに要素を追加すると、その前に要素を追加または削除しない限り、そこに見つけることができます。

いずれかのリスト実装がインデックスに基づく以外の順序で要素を格納する場合、上記のリストメソッドは意味がありません。

3
Costi Ciudatu

List APIの1行目には、順序付きコレクション(シーケンスとも呼ばれる)であると記載されています。リストを並べ替えると順序を維持できないため、JavaにはTreeListはありません。
APIによると、Java ListはSequenceからヒントを得て、シーケンスのプロパティを参照してください http://en.wikipedia.org/wiki/Sequence_(mathematics

リストをソートできないという意味ではありませんが、Javaは彼の定義に厳密に従っており、デフォルトではソートされたバージョンのリストを提供していません。

2
Syam

index-tree-map の使用を検討してください。これは、JDKのTreeSetを拡張したもので、インデックスによる要素へのアクセスを提供し、繰り返しやツリーをバックアップする隠された基礎リストなしで要素のインデックスを見つけることができます。アルゴリズムは、変化があるたびに変化するノードの重みを更新することに基づいています。

1

要素を並べ替える方法を探しているが、インデックスによって効率的な方法でそれらにアクセスできる場合は、次のことができます。

  1. ストレージにランダムアクセスリストを使用します(例:ArrayList
  2. 常にソートされていることを確認してください

次に、要素を追加または削除するには、 Collections.binarySearch を使用して挿入/削除インデックスを取得します。リストはランダムアクセスを実装しているため、決定されたインデックスを使用してリストを効率的に変更できます。

例:

/**
 * @deprecated
 *      Only for demonstration purposes. Implementation is incomplete and does not 
 *      handle invalid arguments.
 */
@Deprecated
public class SortingList<E extends Comparable<E>> {
    private ArrayList<E> delegate;

    public SortingList() {
        delegate = new ArrayList<>();
    }

    public void add(E e) {
        int insertionIndex = Collections.binarySearch(delegate, e);

        // < 0 if element is not in the list, see Collections.binarySearch
        if (insertionIndex < 0) {
            insertionIndex = -(insertionIndex + 1);
        }
        else {
            // Insertion index is index of existing element, to add new element 
            // behind it increase index
            insertionIndex++;
        }

        delegate.add(insertionIndex, e);
    }

    public void remove(E e) {
        int index = Collections.binarySearch(delegate, e);
        delegate.remove(index);
    }

    public E get(int index) {
        return delegate.get(index);
    }
}
0
Marcono1234