Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does map.merge() not call the remapping function every time?

The Map.merge() documenation says:

If the specified key is not already associated with a value or is associated with null, associates it with the given non-null value. Otherwise, replaces the associated value with the results of the given remapping function, or removes if the result is null. This method may be of use when combining multiple mapped values for a key. For example, to either create or append a String msg to a value mapping.

For example, this code should calculate how many fruits of each type there are in a basket:

public static void main(String[] args) {
    Map<String, Integer> fruitCounts = new HashMap<>();
    List<String> fruitBasket = Arrays.asList(
        "Apple", "Banana", "Apple", "Orange", "Mango", "Orange", "Mango", "Mango");
    for (String fruit : fruitBasket) {
        fruitCounts.merge(fruit, 1/*First fruit of this type*/, (k, v) -> v + 1);
    }
    System.out.println(fruitCounts);
}

There are 2 Apples, 3 Mangos, 2 Oranges and 1 Banana but the actual output is:

{Apple=2, Mango=2, Orange=2, Banana=1}

What is wrong?

like image 616
Nilesh Avatar asked Jul 13 '17 03:07

Nilesh


2 Answers

The problem is here

(k, v) -> v + 1

You should be doing

(k, v) -> k + v

If you check the implementation of merge it says, remappingFunction.apply(oldValue, value); means the existing value will be the first parameter in which you should add the same number you initialized it with which comes as a second parameter for that function.

Update

like image 114
Mritunjay Avatar answered Oct 12 '22 18:10

Mritunjay


Completing @Mritunjay answer's, here's an equivalent using compute where you might be able to see the difference:

fruitCounts.compute(fruit, (k,v) -> v == null ? 1 : v + 1) //computing over the value
fruitCounts.merge(fruit, 1, (oldValue, newValue) -> oldValue + 1) //merging over the value
like image 30
Tavo Avatar answered Oct 12 '22 17:10

Tavo