重複するキーがHashMapに入力されるとどうなりますか?


276

同じキーをHashMapputメソッドに複数回渡した場合、元の値はどうなりますか?そして、値が繰り返される場合はどうなりますか?これに関するドキュメントは見つかりませんでした。

ケース1:キーの値を上書き

Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","not one");
mymap.put("1","surely not one");
System.out.println(mymap.get("1"));

我々が得ますsurely not one

ケース2:重複する値

Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","not one");
mymap.put("1","surely not one");
// The following line was added:
mymap.put("1","one");
System.out.println(mymap.get("1"));

我々が得ますone

しかし、他の値はどうなりますか?私は学生に基本を教えていましたが、これを尋ねられました。Map最後の値が参照されている(ただしメモリ内にある)バケットのようなものですか?


7
ところで、これはJakartaコレクションクラス(commons.apache.org/collections)の一部であるマルチハッシュマップを披露する絶好の機会です。必要なときに、同じキーに関連付けられた任意の数の値を持つことができます。
John Munsch、

回答:


303

定義により、このputコマンドは、マップ内の指定されたキーに関連付けられている以前の値を置き換えます(概念的には、プリミティブ型の配列インデックス操作のように)。

マップは、その参照を値にドロップするだけです。オブジェクトへの参照を保持するものが他にない場合、そのオブジェクトはガベージコレクションの対象になります。さらに、Javaは指定されたキーに関連付けられている以前の値を返します(null存在しない場合)。そのため、そこに何があったかを判断し、必要に応じて参照を維持できます。

詳細はこちら:HashMap Doc


これをありがとう。Javaのドキュメントを読んでも、これについては明確に述べられていません。私は、ドキュメントの作成者がこれをすべてのハッシュマップ実装の暗黙の仮定であると想定していたと思います。
Andrew S

77

Map#put(K、V)のjavadoc (実際には何かを返す)で答えを見つけることができます。

public V put(K key,
             V value)

指定された値をこのマップ内の指定されたキーに関連付けます(オプションの操作)。マップにこのキーのマッピングが以前に含まれていた場合、古い値は指定された値に置き換えられます。(マップmkm.containsKey(k)が返される場合に限り、キーのマッピングを含むと言われますtrue。)

パラメータ:
key -指定された値が関連付けられるキー。
value-指定されたキーに関連付けられる値。

戻り値:
指定されたキーに関連付けられている以前の値、またはnullのマッピングがなかった場合key。(実装が値をサポートしている場合、null戻り値はnull、指定されたに以前関連付けられていたマップを示すこともできます。)keynull

したがって、を呼び出すときに戻り値を割り当てmymap.put("1", "a string")ないと、参照されなくなり、ガベージコレクションの対象になります。


3
返される値は、ある前の値(またはnullそう、そう、これは私が何を意味するかあるだけのjavadocで上記の文書化されているように)。それは本当に誤解されますか?
Pascal Thivent 2009年

これは非常に役立ちます。
roottraveller 2017

18

キーの以前の値は削除され、新しい値に置き換えられます。

キーに指定されたすべての値を保持したい場合は、次のようなものを実装することを検討してください。

import org.apache.commons.collections.MultiHashMap;
import java.util.Set;
import java.util.Map;
import java.util.Iterator;
import java.util.List;
public class MultiMapExample {

   public static void main(String[] args) {
      MultiHashMap mp=new MultiHashMap();
      mp.put("a", 10);
      mp.put("a", 11);
      mp.put("a", 12);
      mp.put("b", 13);
      mp.put("c", 14);
      mp.put("e", 15);
      List list = null;

      Set set = mp.entrySet();
      Iterator i = set.iterator();
      while(i.hasNext()) {
         Map.Entry me = (Map.Entry)i.next();
         list=(List)mp.get(me.getKey());

         for(int j=0;j<list.size();j++)
         {
          System.out.println(me.getKey()+": value :"+list.get(j));
         }
      }
   }
}

1
このソリューションの価格は低くなっています。MultiHashMapはapache.commons.collectionsの一部であり、Javaではありません。
wikimix 2015年

17

これはキー/値機能であり、実際の値
を取得したい場合、例の入力されたキーに属する実際の値を取得したい場合、「1」の値を取得したい場合、キーと値の機能は重複しません。それ ?!
これが、すべての値に一意のキーを設定する理由ですが、Java標準libによってトリックを設定することができます。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class DuplicateMap<K, V> {

    private Map<K, ArrayList<V>> m = new HashMap<>();

    public void put(K k, V v) {
        if (m.containsKey(k)) {
            m.get(k).add(v);
        } else {
            ArrayList<V> arr = new ArrayList<>();
            arr.add(v);
            m.put(k, arr);
        }
    }

     public ArrayList<V> get(K k) {
        return m.get(k);
    }

    public V get(K k, int index) {
        return m.get(k).size()-1 < index ? null : m.get(k).get(index);
    }
}


あなたはこのようにそれを使うことができます:

    public static void main(String[] args) {
    DuplicateMap<String,String> dm=new DuplicateMap<>();
    dm.put("1", "one");
    dm.put("1", "not one");
    dm.put("1", "surely not one");
    System.out.println(dm.get("1"));
    System.out.println(dm.get("1",1));
    System.out.println(dm.get("1", 5));
}

と印刷の結果は次のとおりです。

[one, not one, surely not one]
not one
null

正解です。よくやった。あなたは私のプログラミング生活を文字通り救ってくれます:)。
Subin Babu

私もありがとう!通常のマップと同じ機能を実行するには、「削除」メソッドを追加する必要がありましたが、うまくいきました!
JGlass

1
@JGlassはあなたの歓迎する男ですが、これは技術的な解決策ではありません。これはJava標準libで実行できることです。技術的には問題に注意する必要があります。この動作が必要な場合は、解決策ではないと確信しています。キー/値の概念の、そして問題について考え、解決するための論理的な方法を見つける必要があります。とにかく私の詳細は、Javaを使って本番環境で行う楽しい方法です。問題と解決の経路は、楽しい仕事とはかなり異なります。ただし、キー/値の動作が問題ではなく、そのようなデータ構造を持っていることがわかっている場合は、これを使用できます。
java acm

13

指定された値をこのマップ内の指定されたキーに関連付けます。マップに以前にキーのマッピングが含まれていた場合、古い値が置き換えられます。


12

これは、既存の値を置き換え、それぞれのキーのマップに。同じ名前のキーが存在しない場合は、指定された値でキーが作成されます。例えば:

Map mymap = new HashMap();
mymap.put("1","one");
mymap.put("1","two");

出力 キー=「1」、値=「2」

そのため、以前の値は上書きされます。


4

マップがバケツのようなものであったかどうかという質問に対して:いいえ。

これはname=valueペアのリストのようなものnameですが、文字列である必要はありません(ただし、それは可能です)。

要素を取得するには、割り当てられたオブジェクトを返すget()メソッドにキーを渡します。

また、ハッシュマップは、getメソッドを使用してオブジェクトを取得しようとした場合、実際のオブジェクトと指定したオブジェクトを比較しないことを意味します。リストを反復処理してキーを比較する必要があるためです。現在の要素を提供しました。

これは非効率的です。代わりに、オブジェクトの構成に関係なく、両方のオブジェクトからいわゆるハッシュコードを計算し、それらを比較します。2つintのオブジェクト全体(場合によっては非常に複雑なオブジェクト)ではなく、2 つのを比較する方が簡単です。ハッシュコードは、事前定義された長さ(int)を持つ要約のように想像できます。そのため、ハッシュコードは一意ではなく、衝突があります。ハッシュコードのルールは、リンクを挿入したドキュメントに記載されています。

これについて詳しく知りたい場合は、javapractices.comおよびtechnofundo.comの記事をご覧ください。

よろしく


3

私はいつも使っていました:

HashMap<String, ArrayList<String>> hashy = new HashMap<String, ArrayList<String>>();

1つの識別キーに複数のものを適用したい場合。

public void MultiHash(){
    HashMap<String, ArrayList<String>> hashy = new HashMap<String, ArrayList<String>>();
    String key = "Your key";

    ArrayList<String> yourarraylist = hashy.get(key);

    for(String valuessaved2key : yourarraylist){
        System.out.println(valuessaved2key);
    }

}

あなたはいつもこのようなことをして自分で迷路を作ることができます!

public void LOOK_AT_ALL_THESE_HASHMAPS(){
    HashMap<String, HashMap<String, HashMap<String, HashMap<String, String>>>> theultimatehashmap = new HashMap <String, HashMap<String, HashMap<String, HashMap<String, String>>>>();
    String ballsdeep_into_the_hashmap = theultimatehashmap.get("firststring").get("secondstring").get("thirdstring").get("forthstring");
}

2

JDKのマップは、重複したキーの下にデータを格納するためのものではありません。

  • せいぜい新しい値が以前の値を上書きします。

  • 悪いシナリオは例外です(たとえば、ストリームとして収集しようとした場合):

重複なし:

Stream.of("one").collect(Collectors.toMap(x -> x, x -> x))

OK。次のようになります:$ 2 ==> {one = one}

複製されたストリーム:

Stream.of("one", "not one", "surely not one").collect(Collectors.toMap(x -> 1, x -> x))

例外java.lang.IllegalStateException:重複キー1(1つではなく1つの値をマージしようとしました)| Collectors.duplicateKeyException(Collectors.java:133)で Collectors.lambda $ uniqKeysMapAccumulator $ 1(Collectors.java:180)で| ReduceOps $ 3ReducingSink.accept(ReduceOps.java:169)で| Spliterators $ ArraySpliterator.forEachRemaining(Spliterators.java:948)で| AbstractPipeline.copyIntoで(AbstractPipeline.java:484)| AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)で| でReduceOps $ ReduceOp.evaluateSequential(ReduceOps.java:913)| AbstractPipeline.evaluateで(AbstractPipeline.java:234)| ReferencePipeline.collect(ReferencePipeline.java:578)| (#4:1)

重複したキーを処理するには-https: //google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.htmlなどの別のパッケージを使用し ます

重複したキーを処理する他の多くの実装があります。これらはWebに必要です(たとえば、重複したCookieキー、HTTPヘッダーは同じフィールドを持つことができます...)

幸運を!:)


「オーバーライド」操作にはコストがかかりますか?
gaurav

JDKのみを使用して解決できます。Collectors.toMap()3番目の引数-マージ関数があります。我々は、単に最後の重複した要素を上書きする場合:Stream.of("one", "two", "one").collect(Collectors.toMap(x -> x, x -> x, (key1, key2) -> key2))リンク
スタンドアロン型

また、2番目のコード例は正しくありません。この入力:"one", "not one", "surely not one"すべての文字列が異なるため、重複キーエラーは生成されません。
スタンドアロン型

こんにちは、@ stand alone。マッピング機能(toMap)をよくお読みください。
Witold Kaczurba

こんにちは@WitoldKaczurba。投稿する前にコードをコンパイルしてください。
スタンドアロン

1

ところで、このキーが存在しない場合にのみ置くなどのセマンティクスが必要な場合。あなたが使用することができconcurrentHashMapputIfAbsent()機能。これをチェックしてください:

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentHashMap.html#put(K,%20V)

concurrentHashMapロックストライピング」メカニズムを使用してスループットを向上させるため、スレッドセーフで高性能です。


1

はい、これは値を持つすべての1つのキーが最後に追加された値で上書きされることを意味します。ここで「確かに1つではない」を追加すると、「確実に1つではない」だけが表示されます。

ループで表示しようとしても、同じキーを持つ1つのキーと値のみが表示されます。


0
         HashMap<Emp, Emp> empHashMap = new HashMap<Emp, Emp>();

         empHashMap.put(new Emp(1), new Emp(1));
         empHashMap.put(new Emp(1), new Emp(1));
         empHashMap.put(new Emp(1), new Emp());
         empHashMap.put(new Emp(1), new Emp());
         System.out.println(empHashMap.size());
    }
}

class Emp{
    public Emp(){   
    }
    public Emp(int id){
        this.id = id;
    }
    public int id;
    @Override
    public boolean equals(Object obj) {
        return this.id == ((Emp)obj).id;
    }

    @Override
    public int hashCode() {
        return id;
    }
}


OUTPUT : is 1

equalsメソッドとhashCode()メソッドを適切にオーバーライドした場合、ハッシュマップは重複を許可しません。

HashSetは内部的にHashMapも使用します。ソースドキュメントを参照してください

public class HashSet{
public HashSet() {
        map = new HashMap<>();
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.