ジャワにはSortedSet
そしてSortedMap
インターフェース。どちらもJava コレクション フレームワーク要素にアクセスするための並べ替えられた方法を提供します。
しかし、私の理解ではJavaには存在しませんSortedList
。java.util.Collections.sort()
リストを並べ替えます。
なぜそのように設計されているのかご存知ですか?
ベストアンサー1
リスト反復子は、まず第一に、リストの要素をリストの内部順序 (挿入順序とも呼ばれます) で取得することを保証します。より具体的には、要素を挿入した順序、またはリストを操作した方法に従います。ソートはデータ構造の操作と見なすことができ、リストをソートする方法はいくつかあります。
個人的に便利だと思う順に並べます。
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>
。
あるいは、マルチセット(バッグとも呼ばれる)は、Set
重複要素を許可する であり、サードパーティの実装もあります。最も顕著なのは、グアバライブラリそこにはTreeMultiset
、これは とよく似た働きをしますTreeSet
。
2. リストを並べ替えるCollections.sort()
上で述べたように、List
データのソートはデータ構造の操作です。したがって、さまざまな方法でソートされる「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
Javaでは、次のようなsort
実装も提供しています。Comparator
Collator
これはロケールに依存した文字列のソートに便利です。次に例を示します。
Collator usCollator = Collator.getInstance(Locale.US);
usCollator.setStrength(Collator.PRIMARY); // ignores casing
Collections.sort(strings, usCollator);
Java 8以降では、より単純にList#sort
。
strings.sort( usCollator ) ;
並行環境でのソート
ただし、このsort
メソッドの使用は、コレクションインスタンスが操作されるため、並行環境では使いにくいことに注意してください。代わりに不変コレクションの使用を検討する必要があります。これは、GuavaがOrdering
クラスであり、シンプルなワンライナーです。
List<string> sorted = Ordering.natural().sortedCopy(strings);
3. リストをまとめるjava.util.PriorityQueue
Javaにはソートされたリストはありませんが、ソートされたキューはあります。これはおそらく同じように機能します。java.util.PriorityQueue
クラス。
ニコ・ハース氏はコメント欄にリンクを貼った。関連する質問これもこれに答えます。
ソートされたコレクションでは、内部データ構造を操作することはおそらく望ましくないため、PriorityQueue は List インターフェイスを実装しません (要素に直接アクセスできるため)。
PriorityQueue
イテレータに関する注意点
クラスはおよびインターフェースPriorityQueue
を実装しているため、通常どおり反復処理できます。ただし、反復子はソートされた順序で要素を返すことが保証されていません。代わりに (Alderath がコメントで指摘しているように)、空になるまでキューを実行する必要があります。Iterable<E>
Collection<E>
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 つあります。
- メソッドは要素がユーザーが指定したインデックス内に存在することを保証する必要がある
List<E>
ため、インターフェイスの契約に違反します。add
- なぜ車輪の再発明をするのでしょうか? 上記の最初のポイントで指摘したように、代わりに TreeSet または Multiset を使用する必要があります。
ただし、練習として実行したい場合は、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
。