Home > Software engineering >  How to increase HashMap value using merge method in Java?
How to increase HashMap value using merge method in Java?

Time:05-24

I have the following list and use LinkedHashMap and I want to increase the value of the key by 1 (if the key is not present in the map, it starts from 0 and I add 1):

int nums[] = new int[]{4, 10, 5, 4, 2, 10};

Map<Integer, Integer> map = new LinkedHashMap<>();

for (int i = 0; i < nums.length; i  ) {
    int key = nums[i];
    int value = map.getOrDefault(key, 0)   1;

    // I want to use merge method, but have no idea 
    // what should be the 3 rd parameter denoted by "<??????>"
    int value = map.merge(key, 1, <??????>)

    map.put(key, value);
}

However, I want to use merge method, but have no idea what should be the 3 rd parameter denoted by "<??????>" (see the code). So, how can I use merge method in this scenario?

CodePudding user response:

if the key is not present in the map, it starts from 0 and I add 1

In order to start count from zero you can use method compute():

int nums[] = new int[]{4, 10, 5, 4, 2, 10};
    
Map<Integer, Integer> map = new LinkedHashMap<>();
    
for (int num : nums) {
    map.compute(num, (k, v) -> v == null ? 0 : v   1);
}
    
System.out.println(map);

Output:

{4=1, 10=1, 5=0, 2=0}
  • keys 4 and 10 - occur twice and therefore will be associated with the value of 1;
  • keys 5 and 2 - will be encountered only once and therefore get mapped to the value of 0 (as it was required for the keys that were encountered for the first time, i.e. not present in the map)

With map.merge(num, 1, Integer::sum); a key that hasn't been present in the map will be associated with the value of 1 from the beginning (that's why I removed the previously posted code). And then when such key will be encountered second, third, etc. time the bifunction provided as the third argument of merge() will be used and the value will be incremented by one.

CodePudding user response:

The third parameter of the merge method is a BiFunction, i.e. a functional interface accepting two parameters of generic type V (the type of your values) and returning the merge of said values.

Assuming that in your code you're trying to get the frequency of each key, although you wrote "it starts from 0 and I add 1", here is an example of what you were attempting.

The merge operation is up to you, in your case it simply consists in keeping the first value (the one already present within your map), incrementing it by one and ignoring the second value. The merge could also simply consist in summing the first and second values as for each key you're just mapping the value 1.

int nums[] = new int[]{4, 10, 5, 4, 2, 10};

Map<Integer, Integer> map = new LinkedHashMap<>();
for (int i = 0; i < nums.length; i  ) {
    map.merge(nums[i], 1, (v1, v2) -> v1   1);

    //Alternatively summing the two values
    //map.merge(nums[i], 1, (v1, v2) -> v1   v2);
}

System.out.println(map);

However, if your goal was to get the number of key collisions rather than their frequency then the code above still works by simply replacing the value 1 with 0.

int nums[] = new int[]{4, 10, 5, 4, 2, 10};

Map<Integer, Integer> map = new LinkedHashMap<>();
for (int i = 0; i < nums.length; i  ) {
    map.merge(nums[i], 0, (v1, v2) -> v1   1);
}

System.out.println(map);

CodePudding user response:

If only increment/decrement is needed on the integer values, a more economic approach (fewer instances of Integer created) would be to use a mutable integer class as AtomicInteger as the value type.

Increment/Decrement would then be trivial:

Map<String, AtomicInteger> map = new HashMap<>();
// Create a mapping for key "foo" if not exists, then increment
int n = map.computeIfAbsent("foo", (k) -> new AtomicInteger())
    .incrementAndGet(); // or addAndGet() or similar
  • Related