Search code examples
javacollectionsguavamultimap

In Multimap how to return value which has highest occurrence


I have a MultiMap from guava library

Multimap<Integer,String> maps = ArrayListMultimap.create();

      maps.put(1, "foo");
      maps.put(1, "bar");
      maps.put(1, "foo");
      maps.put(2, "Hello");
      maps.put(2, "foo");
      maps.put(2, "World");
      maps.put(2, "World");

In this for the key 1, I need to return value which has the highest occurrence. In the above case, it has to return map as

Expected Result:

[1,foo]
[2,World]

I tried

Stream result1 = maps.keySet().stream() 
                  .map(i -> 
                              maps.get(i).stream() 
                                  .collect(
                                          Collectors.groupingBy(v -> v, Collectors.counting())
                                          )
                                  );

Result:

{{bar=1, foo=2}=1, {Hello=1, foo=1, World=2}=1}

Solution

  • This is not going to be very strait-forward. You first need to group by key, obviously. Then based on that Key you need to find the max occurrences of the corresponding Value (for 1 == foo, for example). The only way to find that max is to traverse the Collection<String> that is mapped to a certain key. This complicates things even more since you use a Multimap and you could easily have things like:

        maps.put(1, "foo");
        maps.put(1, "bar");
        maps.put(1, "bar");
        maps.put(1, "foo");
    

    As such, IMO, this could be written as:

    Map<Integer, List<String>> result =
            maps.keySet()
                .stream()
                .collect(Collectors.toMap(
                    Function.identity(),
                    x -> {
                        Map<String, Long> freqMap = maps.get(x)
                                                        .stream()
                                                        .collect(Collectors.groupingBy(
                                                            Function.identity(),
                                                            Collectors.counting())
                                                        );
                        long max = Collections.max(freqMap.values());
                        return freqMap.entrySet()
                                      .stream()
                                      .filter(y -> y.getValue() == max)
                                      .map(Entry::getKey)
                                      .collect(Collectors.toList());
                    }
                ));
    
    • I first group by Key (1 and 2)
    • Then get the Collection<String> that is mapped to that Key
    • Then compute a Map<String, Long> that represents the frequency of values. For example : ["foo" = 2]; ["bar" = 1]
    • I then look at the max number of occurrences. Since you are using a multimap, you could have a case when ["foo" = 2]; ["bar" = 2], for the same Key, so we need to take both foo and bar as the result.
    • Based on that max, I find out the corresponding values.