JavaにはSortedSet
とSortedMap
インターフェースがあります。どちらもJavaの標準のCollectionsフレームワークに属しており、要素にアクセスするためのソートされた方法を提供します。
しかし、私の理解では、JavaにはSortedList
はありません。 Java.util.Collections.sort()
を使ってリストをソートすることができます。
なぜそれがそのように設計されているのですか?
リスト反復子は、リストの内部順序でリストの要素を取得することを何よりもまず保証します(別名挿入順序)。具体的には、要素を挿入した順序、またはリストを操作した方法です。ソートはデータ構造の操作と見なすことができ、リストをソートするにはいくつかの方法があります。
個人的には有用性の順に方法を並べます。
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
と非常によく似ています。
Collections.sort()
でリストをソートします上記のように、List
sのソートは、データ構造の操作です。そのため、さまざまな方法でソートされる「真実の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);
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"
SortedList
クラスを書く注:これを行う必要はありません。
新しい要素を追加するたびにソートする独自のListクラスを作成できます。これは、実装に応じてかなり重い計算になる可能性があり、無意味です。ただし、2つの主な理由から、演習として行う場合を除きます。
add
メソッドは、ユーザーが指定したインデックスに要素が存在することを保証する必要があるため、List<E>
インターフェイスが持っている契約を破ります。ただし、ここでの演習として開始したい場合のコードサンプルは、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
のデフォルトの実装はUnsupportedOperationException
sをスローします。
リストの概念は自動的にソートされたコレクションの概念と互換性がないからです。 Listのポイントは、list.add(7, elem)
を呼び出した後、list.get(7)
を呼び出すとelem
が返されることです。自動ソートリストでは、要素は任意の位置に配置される可能性があります。
すべてのリストは項目が追加された順(FIFO順)で既に「ソート」されているので、Java.util.Collections.sort()
を使用して、要素の自然順を含む別の順序でそれらを「ソート」することができます。
編集:
データ構造としてのリストは、興味深いのは、項目が挿入された順序であることに基づいています。
集合はその情報を持っていません。
時間を追加して注文したい場合はList
を使用してください。他の基準で並べ替えたい場合は、SortedSet
を使用してください。
SetとMapは非線形データ構造です。リストは線形データ構造です。
ツリーデータ構造SortedSet
とSortedMap
インターフェースはそれぞれused Red-Black tree 実装アルゴリズムを使ってTreeSet
とTreeMap
を実装します。そのため、重複した項目(またはMap
の場合はキー)がないことを確認します。
List
はすでに順序付きコレクションとインデックスベースのデータ構造を保持しています。ツリーはインデックスベースのデータ構造ではありません。Tree
には重複を含めることはできません。List
では、重複する可能性があるので、TreeList
はありません(つまり、SortedList
はありません)。Java.util.Collections.sort()
を使用する必要があります。指定されたリストを、その要素の自然な順序に従って昇順に並べ替えます。2015年4月の時点で、Androidのサポートライブラリに SortedList クラスが追加されました。これはRecyclerView
で動作するように特別に設計されています。これが ブログ投稿 です。
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 を参照してください。
もう1つのポイントは、挿入操作の時間的な複雑さです。リスト挿入の場合、O(1)の複雑さが予想されます。しかし、これはソートされたリストでは保証できませんでした。
そして最も重要な点は、リストはそれらの要素について何も想定していないということです。たとえば、equals
やcompare
を実装していないもののリストを作成できます。
List
インターフェースには、add(int index, E element)
、set(int index, E element)
などのメソッドがあります。契約では、一度位置Xに要素を追加すると、その前に要素を追加または削除しない限り、そこに見つけることができます。
いずれかのリスト実装がインデックスに基づく以外の順序で要素を格納する場合、上記のリストメソッドは意味がありません。
List APIの1行目には、順序付きコレクション(シーケンスとも呼ばれる)であると記載されています。リストを並べ替えると順序を維持できないため、JavaにはTreeListはありません。
APIによると、Java ListはSequenceからヒントを得て、シーケンスのプロパティを参照してください http://en.wikipedia.org/wiki/Sequence_(mathematics )
リストをソートできないという意味ではありませんが、Javaは彼の定義に厳密に従っており、デフォルトではソートされたバージョンのリストを提供していません。
index-tree-map の使用を検討してください。これは、JDKのTreeSetを拡張したもので、インデックスによる要素へのアクセスを提供し、繰り返しやツリーをバックアップする隠された基礎リストなしで要素のインデックスを見つけることができます。アルゴリズムは、変化があるたびに変化するノードの重みを更新することに基づいています。
要素を並べ替える方法を探しているが、インデックスによって効率的な方法でそれらにアクセスできる場合は、次のことができます。
ArrayList
)次に、要素を追加または削除するには、 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);
}
}