给定java hashmap中的键,如何更新值?

lae*_*tis 585 java key hashmap

假设我们有一个HashMap<String, Integer>Java.

对于我找到的每个字符串的存在,如何更新(递增)字符串键的整数值?

人们可以移除并重新进入该对,但开销将是一个问题.
另一种方法是刚刚放置新的一对,旧的一对将被替换.

在后一种情况下,如果与我试图插入的新密钥存在哈希码冲突会发生什么?哈希表的正确行为是为其分配不同的位置,或者在当前存储桶中创建一个列表.

Mat*_*hen 913

map.put(key, map.get(key) + 1);
Run Code Online (Sandbox Code Playgroud)

应该没事.它将更新现有映射的值.请注意,这使用自动装箱.

  • 使用Java 8,可以通过使用`getOrDefault`轻松避免这种情况,例如:`map.put(key,count.getOrDefault(key,0)+ 1);` (77认同)
  • 实际上,这是最强大和可扩展的企业解决方案. (20认同)
  • @Lavir,这不是一个糟糕的解决方案,但不会发现它是最强大和可扩展的.相反,原子整数更具可扩展性. (12认同)
  • 这假设密钥存在,对吧?当它没有时,我得到nullPointer异常. (12认同)
  • @Martin.. map.put(key, map.getOrDefault(key, 0) + 1) (4认同)

dam*_*uar 101

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"));
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用merge方法,其中1是默认值,函数将现有值增加1:

words.merge("hello", 1, Integer::sum);
Run Code Online (Sandbox Code Playgroud)

此外,有一堆其他有用的方法,例如putIfAbsent,getOrDefault,forEach等.

  • 来自 Javadoc:“如果指定键的值存在且非空,则尝试计算新映射”。您可以使用 `compute()` 代替,它也会处理 `null` 值。 (4认同)
  • 我刚刚测试了您的解决方案。第二个,有方法引用的,有效。第一个,即 lambda 表达式,当您的地图的任何值为 `null`(比如 `words.put("hello", null);`)时,无法始终如一地工作,结果仍然是 `null` 而不是 `1 `正如我所料。 (3认同)

ora*_*uiz 48

hashmap.put(key, hashmap.get(key) + 1);
Run Code Online (Sandbox Code Playgroud)

该方法put替换现有密钥的值,如果不存在则将创建它.

  • 不,它不会创建,它会产生`nullPointer Exception`. (50认同)
  • 代码是给定问题的正确答案,但是在接受的答案中发布完全相同的代码一年后发布.区分这个答案的事情是说明put可以创建一个新的条目,它可以,但不是在这个例子中.如果你对一个不存在的键/值使用hashmap.get(key),那么你将获得null,并且当你尝试增加时,正如@smttsp所说它将是NPE.-1 (13认同)
  • 这个答案是对的.NullPointerException用于不存在的键 (7认同)

Chr*_*ull 42

简化的Java 8方式:

map.put(key, map.getOrDefault(key, 0) + 1);
Run Code Online (Sandbox Code Playgroud)

这使用HashMap的方法来检索键的值,但是如果无法检索键,则返回指定的默认值(在本例中为"0").

这在核心Java中得到支持:HashMap <K,V> getOrDefault(Object key,V defaultValue)

  • 如果您使用的是Java 1.8,这是一个更好的选择 (3认同)

Bal*_*usC 28

更换IntegerAtomicInteger并调用的一个incrementAndGet/ getAndIncrement它的方法.

另一种方法是int在你自己的MutableInteger类中包含一个有increment()方法的类,你只需解决一个安全问题.

  • AtomicInteger是一个可变整数,但内置.我很怀疑写自己的MutableInteger是个更好的主意. (35认同)
  • @Peter:确切地说. (2认同)

Pet*_*rey 17

@ Matthew的解决方案是最简单的,并且在大多数情况下表现都很好.

如果您需要高性能,AtomicInteger是一个更好的解决方案ala @BalusC.

但是,更快的解决方案(提供线程安全性不是问题)是使用TObjectIntHashMap,它提供增量(键)方法并使用原语和少于创建AtomicIntegers的对象.例如

TObjectIntHashMap<String> map = new TObjectIntHashMap<String>()
map.increment("aaa");
Run Code Online (Sandbox Code Playgroud)


小智 16

一线解决方案:

map.put(key, map.containsKey(key) ? map.get(key) + 1 : 1);
Run Code Online (Sandbox Code Playgroud)

  • 这不会给现有答案增加任何新内容,是吗? (4认同)

isu*_*uru 13

您可以像下面一样增加,但是您需要检查是否存在,以便不抛出NullPointerException

if(!map.containsKey(key)) {
 p.put(key,1);
}
else {
 p.put(key, map.getKey()+1);
}
Run Code Online (Sandbox Code Playgroud)


小智 9

哈希是否存在(0为值)还是在第一个增量上"放"到地图上?如果它是第一个增量"put",代码应如下所示:

if (hashmap.containsKey(key)) {
    hashmap.put(key, hashmap.get(key)+1);
} else { 
    hashmap.put(key,1);
}
Run Code Online (Sandbox Code Playgroud)


i_a*_*ero 6

可能会有点晚,但这是我的两分钱.

如果您使用的是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]
Run Code Online (Sandbox Code Playgroud)

我们还可以使用另一个方法putIfAbsent来放一个键.如果指定的键尚未与值关联(或映射为null),则此方法将其与给定值相关联并返回null,否则返回当前值.

如果地图是跨线程共享的,那么我们可以使用ConcurrentHashMapAtomicInteger.来自doc:

An 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]
Run Code Online (Sandbox Code Playgroud)

需要注意的一点是,我们正在调用get获取key的值B,然后调用incrementAndGet()其值,这当然是AtomicInteger.我们可以优化它,因为方法putIfAbsent返回密钥的值(如果已经存在):

map2.putIfAbsent("B",new AtomicInteger(0)).incrementAndGet();//[A=0, B=2]
Run Code Online (Sandbox Code Playgroud)

另外,如果我们计划使用AtomicLong,那么根据高争用的文档,LongAdder的预期吞吐量会显着提高,但会占用更高的空间消耗.还要检查这个问题.


小智 5

由于声誉较低,我无法对一些答案发表评论,因此我将发布我应用的解决方案。

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
   }
}
Run Code Online (Sandbox Code Playgroud)


Ser*_*rin 5

没有NullPointerException的更干净的解决方案是:

map.replace(key, map.get(key) + 1);
Run Code Online (Sandbox Code Playgroud)

  • 如果密钥不存在,则map.get(key)将抛出NPE (5认同)