Java8 stream groupingBy enum and counting

末鹿安然 提交于 2019-11-30 21:44:35

You can use the groupingBy collector to create a map but if you want to add default values for absent keys, you have to ensure that the returned map is mutable by providing a Supplier for the map. On the other hand, this adds the opportunity to create an EnumMap which is more suitable to this use case:

EnumMap<Color, Long> map = list.stream().collect(Collectors.groupingBy(
    Person::getFavouriteColor, ()->new EnumMap<>(Color.class), Collectors.counting()));
EnumSet.allOf(Color.class).forEach(c->map.putIfAbsent(c, 0L));

May be, you think it’s cleaner to fill the map with default values within the supplier function:

EnumMap<Color, Long> map = list.stream().collect(Collectors.toMap(
    Person::getFavouriteColor, x->1L, Long::sum, ()->{
        EnumMap<Color, Long> em = new EnumMap<>(Color.class);
        EnumSet.allOf(Color.class).forEach(c->em.put(c, 0L));
        return em;
    }));

but of course, you can also use a stream to create that initial map:

EnumMap<Color, Long> map = list.stream().collect(Collectors.toMap(
    Person::getFavouriteColor, x->1L, Long::sum, () ->
        EnumSet.allOf(Color.class).stream().collect(Collectors.toMap(
        x->x, x->0L, Long::sum, ()->new EnumMap<>(Color.class)))));

But for completeness, you can do the same without the stream API, if you wish:

EnumMap<Color, Long> map = new EnumMap<>(Color.class);
list.forEach(p->map.merge(p.getFavouriteColor(), 1L, Long::sum));
EnumSet.allOf(Color.class).forEach(c->map.putIfAbsent(c, 0L));

You can try with:

Map<Color, Long> counted = list.stream()
        .collect(Collectors.groupingBy(Person::getFavouriteColor(), 
                                       Collectors.counting()));

Of course, this implies that you have a getter for the Person#favouriteColor member.

Then, in order to add the non-existing Colors to the Map, you can stream over all Color values, filter those who are not used as keys for the Map yet and put them with value of 0:

Stream.of(Color.values())
      .filter(x -> !counted.containsKey(x))
      .forEach(x -> counted.put(x, 0L));
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!