6

随着课程:

public class Person {

    private String name;
    private Color favouriteColor;
}

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

使用Java8 List<Person>Stream API 可以将其转换为Map<Color, Long>具有 each 的计数Color,也可以用于未包含在列表中的颜色。例子:

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

使用枚举的所有颜色及其计数在 Map 中转换此列表。

谢谢

解决了

使用自定义收集器解决:

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

2 回答 2

11

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

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

可能是,您认为在供应商函数中使用默认值填充地图更清洁:

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

但当然,您也可以使用流来创建初始地图:

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 的情况下执行相同操作:

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));
于 2015-07-21T13:26:36.003 回答
4

您可以尝试:

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

当然,这意味着您有Person#favouriteColor成员的吸气剂。

然后,为了将不存在Color的 s 添加到 Map,您可以对所有Color值进行流式传输,过滤那些尚未用作 Map 键的值,并将它们的值设置为0

Stream.of(Color.values())
      .filter(x -> !counted.containsKey(x))
      .forEach(x -> counted.put(x, 0L));
于 2015-07-21T11:34:56.950 回答