-2

クエリが 1 つあります。並べ替えたいマップを作成しました。アドバイスをお願いします。

  HashMap map=new HashMap();//HashMap key random order.
     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");
     System.out.println("There are "+map.size()+" elements in the map.");
     System.out.println("Content of Map are...");
     Set s=map.entrySet();
     Iterator itr=s.iterator();
     while(itr.hasNext())
     {
         Map.Entry m=(Map.Entry)itr.next();
         System.out.println(m.getKey()+"\t"+m.getValue()+"\t"+ m.hashCode());
      }
4

2 に答える 2

4

(文字列)キーでソートしたい場合は、java.util.TreeMap代わりにHashMap.

于 2012-04-17T16:41:44.483 に答える
0

実際に必要なソリューションに影響を与える考慮事項がいくつかあります。

を使用しています。これは、タイプ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()TreeSetTreeMapConcurrentSkipListMap

の使用例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あります。ConcurrentSkipListMapCollections.sort

このような順序付けを実現したい場合は、演習として残します。

結論

あなたの質問は、表面的には、あなたのMapようなオブジェクトのデータを並べ替えるだけです。

次のオプションを使用できます。

  • java.util.TreeMap- 自然な順序で要素の順序を維持する
  • java.util.concurrent.ConcurrentSkipListMap- 上記と同じですが、優れたスレッドセーフが付属しています
  • を使用してオンデマンドで並べ替えCollections.sort()

このデータ構造をどのように使用しているのか、またはどの環境で使用されているのかわかりません。たとえば、 へのマルチスレッド アクセスがある場合は、それ自体が持っていないHashMap同期メカニズムが必要です。HashMapそのためには、java.util.concurrent.ConcurrentSkipListMaporの方が使いやすいjava.util.concurrent.ConcurrentHashmapです。

そのため、データの使用方法に応じて、データを並べ替えるさまざまな方法があります。常にソートしたい場合は、ConcurrentSkipListMap(マルチスレッドの場合) またはを使用することをお勧めしTreeMapます。償却された O(1)の挿入パフォーマンスが必要な場合はHashMap、おそらくHashMap「オンデマンド」の方法を使用して並べ替えるか、キーを並べ替えるために別のデータ構造を保持する必要があります。特定の用途でパフォーマンスに懸念がある場合は、プロファイリングを行ってください。

そしていくつかの追加の詳細:

  • 上記のデータ構造をトラバースするために for each ループを使用しています。要素へのアクセスのみが必要な場合 (変更や削除は必要ない場合)、for-each は明示的なイテレータよりも優れたシンタックス シュガーです。
  • HashMap<...> map = new HashMap<...>();私の例では、具体的なクラスではなく、インターフェイスを変数の型として使用しています (コードでは .
于 2012-04-17T21:52:23.760 に答える