如何将地图流转换为单个地图

How to convert Stream of Maps into a single Map

我需要使用流将 Stream<Map<EntityType, Set<String>>> 转换为 Map<EntityType, Set<String>>

EntityType 是一个具有特定值的 enum,比方说 ABC.并且流中有很多地图。

我想使用 Stream API 将它们全部连接成 一个映射 。有什么办法吗?

您可以尝试这样的操作:

public static void main(String[] args) {

    Map<EntityType, Set<String>> mapA = Map.of(EntityType.A, Set.of("1", "2", "3"), EntityType.B, Set.of("4", "5", "6"));
    Map<EntityType, Set<String>> mapB = Map.of(EntityType.A, Set.of("1", "4", "5"), EntityType.C, Set.of("4", "5", "6"));
    Map<EntityType, Set<String>> mapC = Map.of(EntityType.A, Set.of("3", "7", "5"), EntityType.B, Set.of("4", "9", "6"));
    
    // The stream calls you can try:
    Map<EntityType, Set<String>> result = Stream.of(mapA, mapB, mapC)
      .flatMap(map -> map.entrySet().stream())
      .collect(Collectors.toMap(keyValuePair -> keyValuePair.getKey(),
                                keyValuePair -> keyValuePair.getValue(),
                                (value1, value2) -> combine(value1, value2)));
}

private static <T> Set<T> combine(Set<T>... sets) {
    return Stream.of(sets)
      .flatMap(Set::stream)
      .collect(Collectors.toSet());
}

enum EntityType {
    A,
    B,
    C
}

为此,您可以通过应用 flatMap() 展平 流中的 maps。并用 new 包装每个 entry。需要此步骤 1. 以避免源的 突变 2. 防止 UnsupportedOperationException 如果 setsunmodifiable.

将被提升

然后申请collect().

由于 EntityTypeenum,因此 supplier 提供的容器最合适的选择是 EnumMap,它专为 enum-keys 并且性能优于 HashMap.

combine 方法中 merge() 被应用于 结果映射 以将流中的条目添加到其中。

public static <T extends Enum<T>, U> Map<T, Set<U>> collect(Stream<Map<T, Set<U>>> source,
                                                            Class<T> enumClass) {
    return source
            .flatMap(map -> map.entrySet().stream()
                    .map(entry -> Map.entry(entry.getKey(), new HashSet<>(entry.getValue()))))
            .collect(() -> new EnumMap<>(enumClass),
                    (map, entry) -> map.merge(entry.getKey(),
                                              entry.getValue(),
                                              (v1, v2) -> {v1.addAll(v2); return v1;}),
                    Map::putAll);
}

main()

public static void main(String[] args) {
    Stream<Map<EntityType, Set<String>>> source =
            Stream.of(Map.of(EntityType.A, Set.of("foo"), EntityType.B, Set.of("bar")),
                    Map.of(EntityType.A, Set.of("foo", "bar"), EntityType.B, Set.of("bar", "fiz")),
                    Map.of(EntityType.A, Set.of("foobar"), EntityType.B, Set.of("abc", "www")));

    System.out.println(collect(source, EntityType.class));
}

输出

{A=[bar, foobar, foo], B=[bar, abc, fiz, www]}