'Increment an Integer within a HashMap
Do I have to return the object and then put a new one in ? Or can I just directly increment ?
Integer temp = myMap.get(key);
temp++;
myMap.put(key, temp);
there is no way to just do this (this doesn't work) :
myMap.get(key)++;
Solution 1:[1]
This is the shortest code that does this job.
myMap.put(key, myMap.get(key) + 1)
I think it is not too long.
Solution 2:[2]
In Java 8 there are new methods on Map which you can use with lambdas to solve this. First alternative, compute:
a.compute(key, (k, v) -> v+1);
Note that this only works if the hash is initialized for all possible keys.
If this is not guaranteed you can either change the above code to:
a.compute(key, (k, v) -> v == null ? 1 : v + 1);
Or use the merge method (which I would prefer):
a.merge(key, 1, (a, b) -> a + b);
Maybe there are more lambda based methods I am not aware of.
Solution 3:[3]
You can use a mutable integer such as AtomicInteger.
Map<Key, AtomicInteger> myMap = new HashMap<Key, AtomicInteger>();
myMap.get(key).incrementAndGet();
Or you can use Trove4j which supports primitives in collections.
TObjectIntHashMap<Key> myMap;
myMap.increment(key);
Solution 4:[4]
You can't directly increment it, because it is immutable. You have to increment it and put the new object back.
Auto boxing is also interfering here. In fact what's happening is something similar to:
Integer i1 = getFromMap();
i1 = Integer.valueOf(++ i1.intValue());
So here your reference points to a new object. You have to put that object back in the map, under the same key.
Solution 5:[5]
As Integer are immutable, yes, you have to do it that way.
If you really want to increment it directly, you'll have to write your own mutable class.
Solution 6:[6]
If you have to do this more than twice you'd prefer to create a tiny class like:
public class MappedCounter {
private Map<String, Integer> map = new HashMap<String, Integer>();
public void addInt(String k, int v) {
if (!map.containsKey(k)) map.put(k, v);
else map.put(k, map.get(k) + v);
}
public int getInt(String k) {
return map.containsKey(k) ? map.get(k) : 0;
}
public Set<String> getKeys() {
return map.keySet();
}
}
Solution 7:[7]
Here are solutions using a Map (Java 8+), and a primitive Map and Bag using Eclipse Collections (EC).
JDK Map
Map<String, Integer> map = new HashMap<>();
map.merge("item", 1, Integer::sum);
Integer count = map.getOrDefault("item", 0);
EC Primitive Map
MutableObjectIntMap<String> map = ObjectIntMaps.mutable.empty();
map.addToValue("item", 1);
int count = map.getIfAbsent("item", 0);
EC Bag
MutableBag<String> bag = Bags.mutable.empty();
bag.add("item");
int count = bag.occurrencesOf("item");
The benefit of the primitive Map or Bag (which wraps a primitive Map) is that there is no boxing of the count values, and adding is explicit in both method names (addToValue / add). A Bag is a better data structure IMO if you want to simply count things.
Note: I am a committer for Eclipse Collections.
Solution 8:[8]
First of all: be aware of unboxing: the temp is from type Integer. But the operation ++ is implemented for int. So temp is unboxed to type int. This means if temp is null you run in a NullPointerException.
And you have to do it like you discripted in your first code block.
Solution 9:[9]
I use the below code and it works but at the beginning you need to define a BiFunction describing that the operation is incrementing by 1.
public static Map<String, Integer> strInt = new HashMap<String, Integer>();
public static void main(String[] args) {
BiFunction<Integer, Integer, Integer> bi = (x,y) -> {
if(x == null)
return y;
return x+y;
};
strInt.put("abc", 0);
strInt.merge("abc", 1, bi);
strInt.merge("abc", 1, bi);
strInt.merge("abc", 1, bi);
strInt.merge("abcd", 1, bi);
System.out.println(strInt.get("abc"));
System.out.println(strInt.get("abcd"));
}
output is
3
1
Solution 10:[10]
Just for completeness in Java 8 there is a longAdder which brings some benefits in comparison to AtomicInteger (http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/LongAdder.html)
final Map<WhatEver, LongAdder> result = new HashMap<>();
result.get(WhatEver).increment();
Solution 11:[11]
This should work
// If the key you want to add does not exist then add it as a new key
// And make the value 1
if (map.get(key) == null) {
map.put(key, 1);
} else {
// If the key does exist then replace the key's value with it's
// Original value plus one
map.put(key, map.get(key) + 1);
}
Solution 12:[12]
Found this to be the best way, avoiding NPE.
Map<Integer, Integer> map = new HashMap<>();
map.put(5, map.getOrDefault(5, 0) + 1);
System.out.println(map.get(5));
Output:
1
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
