Java8流分组通过枚举和计数 [英] Java8 stream groupingBy enum and counting

查看:309
本文介绍了Java8流分组通过枚举和计数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用类:

public class Person {

    private String name;
    private Color favouriteColor;
}

public enum Color {GREEN, YELLOW, BLUE, RED, ORANGE, PURPLE}

使用Java8 Stream API获得 List< Person> 可以在 Map< Color,Long>中进行转换。 具有每个 Color 的计数,也用于未包含在列表中的颜色。
示例:

Having a List<Person> using the Java8 Stream API can I trasform it in a Map<Color, Long> having the count of each Color, also for the color that aren't included in the list. Example:

List<Person> list = List.of(
    new Person("Karl", Color.RED),
    new Person("Greg", Color.BLUE),
    new Person("Andrew", Color.GREEN)
);

在地图中使用所有在enum的颜色中转换此列表他们的数量。

Trasforming this list in a Map with all the colors of the enum with their count.

谢谢

已解决

使用自定义收集器解决:

Solved using a custom collector:

public static <T extends Enum<T>> Collector<T, ?, Map<T, Long>> counting(Class<T> type) {
    return Collectors.toMap(
        Function.<T>identity(),
        x -> 1l,
        Long::sum,
        () -> new HashMap(Stream.of(type.getEnumConstants()).collect(Collectors.toMap(Function.<T>identity(),t -> 0l)))
    );
}


list.stream()
    .map(Person::getFavouriteColor)
    .collect(counting(Color.class))


推荐答案

你可以使用 groupingBy 收集器用于创建映射但是如果要为缺少的键添加默认值,则必须通过提供 Supplier 来确保返回的映射是可变的地图。另一方面,这增加了创建 EnumMap 的机会,这更适合这个用例:

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)))));

但是为了完整性,如果您愿意,可以在没有流API的情况下执行相同操作:

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));

这篇关于Java8流分组通过枚举和计数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆