Search code examples
javalambdajava-8java-streamcollectors

Java8 Stream List<Map<String,Object>> groupingBy and counting value


i want get result like { "key1" : 4 ,"key2" :2 }

i known i can use map and groupby and such as

list.stream()
    .map(map -> map2Entity(map))
    .collect(Collectors.groupingBy(Entity::getKey,Collectors.summarizingInt(Entity::getCnt)) )

This is my code and how implements (todo) code

public void test() {
    List<Map<String, Object>> list = Arrays.asList(
            createNewMap("key1", 1),
            createNewMap("key2", 2),
            createNewMap("key1", 3)
    );
    // i want get result like {"key1":4,"key2":2}
    // how can i get the result don't use map()
    list.stream()
                .collect(Collectors.groupingBy(this::getKey),....(todo));
}

private String getKey(Map<String,Object> map){
    return  (String) map.get("key");
}

private Map<String, Object> createNewMap(String key, Integer val) {
    Map<String, Object> map = new HashMap<>();
    map.put("key", key);
    map.put(key, val);
    return map;
}

Solution

  • You have to use the flatMap operator along with the groupingBy collector. Here's how it looks.

    Map<String, Integer> keyToSumValuesMap = list.stream()
        .flatMap(m -> m.entrySet().stream())
        .collect(Collectors.groupingBy(Map.Entry::getKey, 
            Collectors.summingInt(Map.Entry::getValue)));
    

    Moreover do not use Object type to represent integers since that is not type safe. Consider declaring method level generics to overcome that issue. Here's how it looks.

    private static <S, T> Map<S, T> createNewMap(S key, T val) {
        Map<S, T> map = new HashMap<>();
        map.put(key, val);
        return map;
    }
    

    And the output now looks like this:

    {key1=4, key2=2}