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