简体   繁体   中英

How to convert Stream of Maps into a single Map

I need to use streams to convert the Stream<Map<EntityType, Set<String>>> to Map<EntityType, Set<String>> .

The EntityType is an enum having certain values, let's say A , B and C . And there are lots of maps in the stream.

I want to concatenate all of them into one map using Stream API . Is there any way?

You could try something like this:

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
}

For that, you can flatten the maps in the stream by applying flatMap() . And wrap each entry with a new one. This step is required 1. to avoid mutation of the source and 2. to prevent an UnsupportedOperationException which will be raised if sets are unmodifiable .

And then apply collect() .

Since EntityType is an enum the most appropriate choice for the container provided by the supplier will be an EnumMap which was designed specifically for enum-keys and has a better performance than HashMap .

Inside the combine method merge() is being applied on the resulting map to add entries from the stream into it.

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

Output

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM