Java 如何使用流合并地图集合

Java 如何使用流合并地图集合,java,java-8,java-stream,Java,Java 8,Java Stream,我有一套地图: Collection<Map<String,Double>> myCol = table.values(); 但是,我想使用streams从集合中获取地图。我尝试了以下方法: Map<String, Double> outMap = new HashMap<>(); myCol.stream().forEach(e-> outMap.putAll(mergeMaps(outMap,e))); return outMa

我有一套地图:

Collection<Map<String,Double>> myCol = table.values();
但是,我想使用streams从集合中获取地图。我尝试了以下方法:

Map<String, Double> outMap = new HashMap<>();    
myCol.stream().forEach(e-> outMap.putAll(mergeMaps(outMap,e)));
return outMap;
Map<String, Double> outMap = TreeMap<>();
myCol.forEach(map -> map.forEach((k, v) -> outMap.merge(k, v, Double::sum)));
Map outMap=newhashmap();
myCol.stream().forEach(e->outMap.putAll(mergeMaps(outMap,e));
返回地图;

这是毫无问题的。但是,我还能改进它吗?我的意思是,如何在其中使用收集器?

从您的输入中,您可以获取地图流,然后将其平面映射为
流。然后,将它们收集到一个新映射中,指定要对映射到同一个键的值求和

 myCol.stream()
        .flatMap(x -> x.entrySet().stream())
        .collect(Collectors.groupingBy(
                Entry::getKey, 
                TreeMap::new, 
                Collectors.summingDouble(Entry::getValue)));
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.summingDouble;
import static java.util.stream.Collectors.toMap;

....

Map<String, Double> outMap = 
    myCol.stream()
         .flatMap(m -> m.entrySet().stream())
         .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, Double::sum));

好的,其他建议的解决方案表明纯流解决方案很短,但是如果您想使用现有的merge函数(例如,因为在其他情况下它更复杂),您可以将其交给
流。reduce

Optional<Map<String, Double>> outMap = myCol.stream().reduce((m1, m2) -> mergeMaps(m1, m2));
Optional outMap=mycl.stream().reduce((m1,m2)->合并映射(m1,m2));
使用forEach的初始方法几乎是streamyfied for循环,违反了函数没有副作用的概念。reduce(或上述收集)在内部处理所有数据合并,而不更改输入收集。

对于流:

Map<String, Double> outMap = myCol.stream()
    .flatMap(map -> map.entrySet().stream())
    .collect(Collectors.toMap(
        Map.Entry::getKey,   // key of the result map
        Map.Entry::getValue, // value of the result map
        Double::sum,         // how to merge values for equal keys
        TreeMap::new));      // the type of map to be created

您能解释一下
toMap
groupingBy
的优点和缺点吗?绩效是否存在根本性差异?从可读性的角度来看,我更喜欢
groupingBy
方法,但这只是我的观点。@MalteHartwig关于这个用例,我不期望有太大的性能差异(同样,只有正确的测量才能说明真相)。
groupingBy
的优点是,如果您需要更复杂的缩减,并且正如您所说的,它更具表现力,您可以链接下游收集器。您好!有副作用的函数没有错。在流中使用时不鼓励使用它们,但在
forEach
中使用它们是绝对正确的。另一方面,您使用
reduce
的解决方案每一步都会创建一个新的映射,这可能不是最好的。现在我仔细研究一下,原来的问题也有同样的问题:正在为合并的每一对映射创建一个新的中间映射。是的,但是您可以通过使用带有标识的
reduce
来防止这种情况,而
merge
方法使用第一个映射作为结果。还有一个优点是有保证的回报值。@Federicoperaltachaffner关于副作用的部分可能有点苛刻。我的意思是,最初的方法还没有真正充分利用streams。创建一个只调用forEach的集合流会立即导致不必要的开销,并且不会利用流API的其余部分。可能有点类似-->
.collect(groupingBy(Map.Entry::getKey, summingDouble(Map.Entry::getValue)));
Optional<Map<String, Double>> outMap = myCol.stream().reduce((m1, m2) -> mergeMaps(m1, m2));
Map<String, Double> outMap = myCol.stream()
    .flatMap(map -> map.entrySet().stream())
    .collect(Collectors.toMap(
        Map.Entry::getKey,   // key of the result map
        Map.Entry::getValue, // value of the result map
        Double::sum,         // how to merge values for equal keys
        TreeMap::new));      // the type of map to be created
Map<String, Double> outMap = TreeMap<>();
myCol.forEach(map -> map.forEach((k, v) -> outMap.merge(k, v, Double::sum)));