実際に必要なソリューションに影響を与える考慮事項がいくつかあります。
を使用しています。これは、タイプHashMap<K, V>
の関連付けとキー検索動作が必要であることを意味します。Map
HashMap
キーと値のペアを挿入するたびに、キーのhashCode()
メソッドが呼び出され、マップはそのハッシュ コードを使用してペアリングを格納します。String
オブジェクトにはすでに正しいhashCode()
実装があるため、問題なくキーとして使用できます。
もちろん、 を取得または反復する場合HashMap
、ハッシュ マップはハッシュ コードによってアイテムを格納し、オブジェクトを追加/削除するたびに順序が変わる可能性があるため、かなりランダムな順序で物事を取得します。
データを「並べ替え」たいので、ペアリングをキー順に並べ替えて(入力した名前で並べ替えて)戻すことを意味していると思います。
ここで考慮すべき点は次のとおりです。
データを常にソートする
データを常に並べ替えたい場合、つまり新しいキーと値のペアを挿入するたびに、要素の自然な順序を維持したい場合は、Java API に使用できる便利なデータ構造がいくつかあります。
使用するTreeMap
Dilum が既に述べたように、マップ内のキーの順序を保証するインターフェースjava.util.TreeMap
を実装するを使用できます。java.util.SortedMap
例:
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
public class SortedMapExample {
public static void main(String[] args) {
SortedMap<String, String> map = new TreeMap<String, String>();
map.put("Amit","Java");
map.put("Saral","J2EE");
map.put("ty","Spring");
map.put("Anupam","Hibernate");
map.put("Ravi",".Net");
map.put("Saral","Andriod");//same key but different value
map.put("Nitin","PHP");
map.put("hj","Spring1");
for (Map.Entry<String, String> e : map) {
System.out.println(String.format("%s - %s", e.getKey(), e.getValue()));
}
}
}
このコードを実行すると、これが返されます。
λ > java SortedMapExample
Amit - Java
Anupam - Hibernate
Nitin - PHP
Ravi - .Net
Saral - Andriod
hj - Spring1
ty - Spring
使用するConcurrentSkipListMap
ConcurrentSkipListMapは新しいデータ構造であり、Java 6 で最初に使用可能になりました。また、SortedMap
インターフェースを実装し、基礎となる実装にはスキップ リストが含まれます。
これは並行コレクションでもあります。詳細については、Brian Goetz の記事を参照してください。Java Concurrent Collections はjava.util.concurrent
にあり、簡単に言うと、高性能のスレッドセーフなコレクションです。
を使用するように前の例を変更するのは簡単ConcurrentSkipListMap
です。
import java.util.Map;
import java.util.SortedMap;
import java.util.concurrent.ConcurrentSkipListMap; // this changed
public class SortedMapExample {
public static void main(String[] args) {
// the following line changed - now you know the power of programming to interfaces
SortedMap<String, String> map = new ConcurrentSkipListMap<String, String>();
map.put("Amit","Java");
map.put("Saral","J2EE");
map.put("ty","Spring");
map.put("Anupam","Hibernate");
map.put("Ravi",".Net");
map.put("Saral","Andriod");//same key but different value
map.put("Nitin","PHP");
map.put("hj","Spring1");
for (Map.Entry<String, String> e : map) {
System.out.println(String.format("%s - %s", e.getKey(), e.getValue()));
}
}
}
このコードを実行すると、まったく同じ出力が得られます。
λ > java SortedMapExample
Amit - Java
Anupam - Hibernate
Nitin - PHP
Ravi - .Net
Saral - Andriod
hj - Spring1
ty - Spring
オンデマンドでの並べ替え
おそらく、あなたのユースケースでは、データを常にソートしたままにしたくないでしょう。たぶんそれはパフォーマンスの問題であり (それが問題である場合はベンチマークしてください)、要求されたときにのみデータを並べ替える必要があります。
あなたの場合、Collections.sort
データのキーで使用できます。
あなたの例に固執するHashMap
:
import java.util.Collections;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
public class UnsortedExample {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("Amit", "Java");
map.put("Saral","J2EE");
map.put("ty","Spring");
map.put("Anupam","Hibernate");
map.put("Ravi",".Net");
map.put("Saral","Andriod");//same key but different value
map.put("Nitin","PHP");
map.put("hj","Spring1");
List<String> keys = new ArrayList<String>(map.keySet());
Collections.sort(keys);
for (String key : keys) {
System.out.println(String.format("%s - %s", key, map.get(key)));
}
}
}
ここでは、マップから を取得しました。マップ内のすべてのキーを含むオブジェクトがkeySet()
返されます。Set
次に、それを に変換しArrayList
てリストをソートし、リストを反復処理してマップから値を取り出しました。
、 、 、java.util.TreeSet
を抜くときにも使えます。keySet()
TreeSet
TreeMap
ConcurrentSkipListMap
の使用例SortedSet
:
java.util.SortedSet<String> keys = new java.util.TreeSet<String>(map.keySet());
余談java.util.concurrent.ConcurrentHashMap
ですが、Java Concurrency バージョンのクラスもあり、java.util.HashMap
同時アクセスが発生するマルチスレッド環境で非常にうまく機能します。
おっと、なぜ順序が変なのですか?
この例では英語を使用しています (英語以外の「並べ替えられた」言語についてはよくわかりません) が、順序に奇妙な点があることがわかります。
たとえば、前の例の出力では、が の"hj"
後"Saral"
に来ましたが、人間はおそらくリストを本当にアルファベット順に並べ、と"hj"
の間に来るように"Anupam"
し"Nitin"
ます。
デフォルトでjava.lang.String
は、インターフェースを実装し、自然順序付けをComparable
定義します。Java は、使用されている他のほとんどすべてのプログラミング言語と同様に、大文字の英字を小文字の前に並べます。
簡単な説明は、ASCII/UTF-8 では、英語の大文字が英語の小文字の前に来るということです。
ただし、大文字と小文字を区別しない別のアルファベット順の並べ替えが必要になる場合があります。そのためには、 を実装する独自のクラスを作成しComparator
、それを または のコンストラクター、またはコンパレーター オブジェクトを受け取るメソッドに渡す必要がTreeMap
あります。ConcurrentSkipListMap
Collections.sort
このような順序付けを実現したい場合は、演習として残します。
結論
あなたの質問は、表面的には、あなたのMap
ようなオブジェクトのデータを並べ替えるだけです。
次のオプションを使用できます。
java.util.TreeMap
- 自然な順序で要素の順序を維持する
java.util.concurrent.ConcurrentSkipListMap
- 上記と同じですが、優れたスレッドセーフが付属しています
- を使用してオンデマンドで並べ替え
Collections.sort()
このデータ構造をどのように使用しているのか、またはどの環境で使用されているのかわかりません。たとえば、 へのマルチスレッド アクセスがある場合は、それ自体が持っていないHashMap
同期メカニズムが必要です。HashMap
そのためには、java.util.concurrent.ConcurrentSkipListMap
orの方が使いやすいjava.util.concurrent.ConcurrentHashmap
です。
そのため、データの使用方法に応じて、データを並べ替えるさまざまな方法があります。常にソートしたい場合は、ConcurrentSkipListMap
(マルチスレッドの場合) またはを使用することをお勧めしTreeMap
ます。償却された O(1)の挿入パフォーマンスが必要な場合はHashMap
、おそらくHashMap
「オンデマンド」の方法を使用して並べ替えるか、キーを並べ替えるために別のデータ構造を保持する必要があります。特定の用途でパフォーマンスに懸念がある場合は、プロファイリングを行ってください。
そしていくつかの追加の詳細:
- 上記のデータ構造をトラバースするために for each ループを使用しています。要素へのアクセスのみが必要な場合 (変更や削除は必要ない場合)、for-each は明示的なイテレータよりも優れたシンタックス シュガーです。
HashMap<...> map = new HashMap<...>();
私の例では、具体的なクラスではなく、インターフェイスを変数の型として使用しています (コードでは、 .