将一组地图流式传输到一个地图中

时间:2018-06-04 06:38:39

标签: java dictionary java-8 java-stream collectors

我有一组地图。内部地图可以包含匹配的键,因此我想将其转换为Map Collection

Collection<Map<String, Thing>> =&gt; Map<String, Collection<Thing>>

我尝试的是:

Map<String, Collection<Thing>> newMap = oldCollection
    .stream()
    .map(Map::entrySet)
    .collect(Collectors.groupingBy(
             Entry::getKey,
             Collectors.mapping(Entry::getValue, Collectors.toList())));

我觉得这应该可行,但我收到编译错误:

Type mismatch: cannot convert from Map<Object,List<Object>> to Map<String,Collection<Thing>>

有谁知道我做错了什么?

4 个答案:

答案 0 :(得分:3)

oldCollection.stream().map(Map::entrySet)创建Stream<Set<Map.Entry<String,Thing>>>,但您需要Stream<Map.Entry<String,Thing>>

因此您需要使用flatMap

Map<String, List<Thing>>
    newMap = oldCollection.stream()
                          .flatMap(m->m.entrySet().stream())
                          .collect(Collectors.groupingBy(Map.Entry::getKey, 
                                                         Collectors.mapping(Map.Entry::getValue,
                                                                            Collectors.toList())));

此外,由于您要将分组值映射到List,因此输出类型应为Map<String, List<Thing>>

如果您想保留当前的输出类型,可以将Collectors.toList()更改为Collectors.toCollection(ArrayList::new)

答案 1 :(得分:1)

或者你也可以这样做,

final Map<String, List<Thing>> thingsMap = oldCollection.stream()
        .map(Map::entrySet)
        .flatMap(Set::stream)
        .collect(Collectors.groupingBy(
            Map.Entry::getKey,
            Collectors.mapping(
                Map.Entry::getValue,  
                Collectors.toList()
            )
        ));

你可以获得每个地图的入口集,你得到一组集合,然后你展平它们以从它们中获得一个大的流。最后你处理那个大流。

答案 2 :(得分:1)

为了比较,这是循环解决方案:

Map<String, Collection<Thing>> newMap = new HashMap<>();
for(Map<String, Thing> m: oldCollection)
    m.forEach((s,t) -> newMap.computeIfAbsent(s, x->new ArrayList<>()).add(t));

您可以表达与Stream操作相同的逻辑:

Map<String, Collection<Thing>> newMap = oldCollection
    .stream()
    .collect(HashMap::new,
             (r,m)->m.forEach((s,t)->r.computeIfAbsent(s,x->new ArrayList<>()).add(t)),
             (r,m)->m.forEach((s,l)->r.computeIfAbsent(s,x->new ArrayList<>()).addAll(l)));

除了flatMap的逻辑已集成到收集器中之外,其他解决方案也是如此。

答案 3 :(得分:0)

首先创建地图可能更简单:

Map<String, Collection<Thing>> map = new HashMap<>();

oldCollection.stream()
    .map(Map::entrySet)
    .flatMap(Set::stream)
    .forEach(e -> map.computeIfAbsent(e.getKey(), k -> new ArrayList<>()).add(e.getValue()));