web-dev-qa-db-ja.com

Javaハッシュマップのキーを指定して値を更新する方法

JavaにHashMap<String, Integer>があるとします。

見つかった文字列が存在するたびに、文字列キーの整数値を更新(増分)するにはどうすればよいですか。

ペアを削除して再入力することもできますが、オーバーヘッドが問題になります。
別の方法は、新しいペアを置くだけで、古いペアを置き換えることです。

後者の場合、挿入しようとしている新しいキーとハッシュコードが衝突した場合はどうなりますか?ハッシュテーブルの正しい振る舞いは、それに別の場所を割り当てるか、現在のバケットの中でそれからリストを作ることです。

552
laertis
map.put(key, map.get(key) + 1);

大丈夫です。既存のマッピングの値が更新されます。これはオートボクシングを使用していることに注意してください。

863

Java 8の方法:

computeIfPresentメソッドを使用して、それにマッピング関数を指定することができます。マッピング関数は、既存の値に基づいて新しい値を計算するために呼び出されます。

例えば、

Map<String, Integer> words = new HashMap<>();
words.put("hello", 3);
words.put("world", 4);
words.computeIfPresent("hello", (k, v) -> v + 1);
System.out.println(words.get("hello"));

代わりに、mergeメソッドを使用することもできます。ここで、1はデフォルト値で、関数は既存の値を1ずつ増やします。

words.merge("hello", 1, Integer::sum);

さらに、putIfAbsentgetOrDefaultforEachなど、他にもたくさんの便利な方法があります。

86
damluar
hashmap.put(key, hashmap.get(key) + 1);

メソッドput replace を既存のキーの値とし、存在しない場合はそれを作成します。

49
oracleruiz

簡略化された Java 8 way:

map.put(key, map.getOrDefault(key, 0) + 1);

これは、キーの値を取得するHashMapのメソッドを使用しますが、キーを取得できない場合は、指定されたデフォルト値(この場合は「0」)を返します。

これはコアJava内でサポートされています: HashMap <K、V> getOrDefault(オブジェクトキー、V defaultValue)

31

IntegerAtomicInteger に置き換え、その上でincrementAndGet/getAndIncrementメソッドのいずれかを呼び出します。

別の方法はincrement()メソッドを持つあなた自身のintクラスでMutableIntegerをラップすることです、あなたはまだ解決するべきスレッドセーフティの懸念があるだけです。

27
BalusC

@ Matthewのソリューションは最も簡単で、ほとんどの場合十分に機能します。

高性能が必要な場合は、AtomicIntegerが@BalusCより優れたソリューションです。

ただし、より高速な解決策(スレッドの安全性が問題にならない場合)は TObjectIntHashMap を使用することです。これはincrement(key)メソッドを提供し、AtomicIntegersを作成するよりもプリミティブを使用しオブジェクトを少なくします。例えば.

TObjectIntHashMap<String> map = new TObjectIntHashMap<String>()
map.increment("aaa");
17
Peter Lawrey

1行ソリューション

map.put(key, map.containsKey(key) ? map.get(key) + 1 : 1);
16
Punktum

以下のようにインクリメントできますが、存在を確認してNullPointerExceptionがスローされないようにする必要があります。

if(!map.containsKey(key)) {
 p.put(key,1);
}
else {
 p.put(key, map.getKey()+1);
}
11
isuru

ハッシュは存在しますか(値が0である)、それとも最初の増分でマップに「入れられる」か。最初のインクリメントで "put"されている場合、コードは次のようになります。

if (hashmap.containsKey(key)) {
    hashmap.put(key, hashmap.get(key)+1);
} else { 
    hashmap.put(key,1);
}
9
sudoBen

それは少し遅くなるかもしれませんが、ここに私の2セントです。

Java 8を使用している場合は、 computeIfPresent メソッドを使用できます。指定されたキーの値が存在し、nullでない場合は、キーとその現在のマップ値を指定して新しいマッピングを計算しようとします。

final Map<String,Integer> map1 = new HashMap<>();
map1.put("A",0);
map1.put("B",0);
map1.computeIfPresent("B",(k,v)->v+1);  //[A=0, B=1]

キーを置くために別のメソッド putIfAbsent を利用することもできます。指定されたキーがまだ値に関連付けられていない(またはnullにマッピングされている)場合、このメソッドはそれを指定された値に関連付けてnullを返し、そうでない場合は現在の値を返します。

マップがスレッド間で共有されている場合は、ConcurrentHashMapおよび AtomicInteger を使用できます。ドキュメントから:

AtomicIntegerはアトミックに更新できるint値です。 AtomicIntegerは、アトミックインクリメントカウンタなどのアプリケーションで使用され、Integerの代わりには使用できません。ただし、このクラスはNumberを拡張して、数値ベースのクラスを扱うツールやユーティリティによる統一的なアクセスを可能にします。

私達は示されているようにそれらを使用することができます:

final Map<String,AtomicInteger> map2 = new ConcurrentHashMap<>();
map2.putIfAbsent("A",new AtomicInteger(0));
map2.putIfAbsent("B",new AtomicInteger(0)); //[A=0, B=0]
map2.get("B").incrementAndGet();    //[A=0, B=1]

注意すべき点の1つは、キーgetの値を取得するためにBを呼び出してから、その値に対してもちろんAtomicIntegerであるincrementAndGet()を呼び出すことです。メソッドputIfAbsentがすでに存在する場合はキーの値を返すので、これを最適化できます。

map2.putIfAbsent("B",new AtomicInteger(0)).incrementAndGet();//[A=0, B=2]

ちなみに AtomicLong を使用する予定がある場合は、競合が激しい場合のドキュメントのとおり、 LongAdder のスループットが大幅に高くなりますが、スペースの消費は増えます。これもチェックしてください question

5
i_am_zero

NullPointerExceptionを使わないでよりきれいな解決策は:

map.replace(key, map.get(key) + 1);
5
Sergey Dirin

インデックスを増やすにはforループを使います。

for (int i =0; i<5; i++){
    HashMap<String, Integer> map = new HashMap<String, Integer>();
    map.put("beer", 100);

    int beer = map.get("beer")+i;
    System.out.println("beer " + beer);
    System.out ....

}
2
VanHoutte

この質問に対する誤解を招くような答えがあります。キーが存在する場合、Hashtableのputメソッドが既存の値を置き換えることを意味します。これはHashtableではなくHashMapに当てはまります。 HashMapのJavadocを参照してください http://docs.Oracle.com/javase/7/docs/api/Java/util/HashMap.html#put%28K,%20V%29

1
user1048218

評判が悪いためにいくつかの回答にコメントすることはできないので、私は自分が適用した解決策を投稿します。

for(String key : someArray)
{
   if(hashMap.containsKey(key)//will check if a particular key exist or not 
   {
      hashMap.put(hashMap.get(key),value+1);// increment the value by 1 to an already existing key
   }
   else
   {
      hashMap.put(key,value);// make a new entry into the hashmap
   }
}
1
aayush nigam

Java 8組み込み関数 'computeIfPresent'を使用

例:

public class ExampleToUpdateMapValue {

    public static void main(String[] args) {
        Map<String,String> bookAuthors = new TreeMap<>();
        bookAuthors.put("Genesis","Moses");
        bookAuthors.put("Joshua","Joshua");
        bookAuthors.put("Judges","Samuel");

        System.out.println("---------------------Before----------------------");
        bookAuthors.entrySet().stream().forEach(System.out::println);
        // To update the existing value using Java 8
        bookAuthors.computeIfPresent("Judges", (k,v) -> v = "Samuel/Nathan/Gad");

        System.out.println("---------------------After----------------------");
        bookAuthors.entrySet().stream().forEach(System.out::println);
    }
}
0
Rajesh Samson

試してください:

HashMap hm=new HashMap<String ,Double >();

注意:

String->give the new value; //THIS IS THE KEY
else
Double->pass new value; //THIS IS THE VALUE

ハッシュマップのキーまたは値を変更することはできますが、両方を同時に変更することはできません。

0
NARAYANAN.M
Integer i = map.get(key);
if(i == null)
   i = (aValue)
map.put(key, i + 1);

または

Integer i = map.get(key);
map.put(key, i == null ? newValue : i + 1);

整数はプリミティブデータ型 http://cs.fit.edu/~ryan/Java/language/Java-data.html なので、取り出す必要があります。何らかの処理を行ってから元に戻す必要があります。 Primitiveデータ型ではない値がある場合は、取り出して処理するだけでよく、ハッシュマップに戻す必要はありません。

0
Kreedz Zhen