Reputation: 565
I'm working on a Java 8 stream. And I need group by 2 keys in a map. And then put these keys with their value into a new function.
Is there a way to skip the Collector
and reading it out again?
graphs.stream()
.map(AbstractBaseGraph::edgeSet)
.flatMap(Collection::stream)
.collect(Collectors.groupingBy(
graph::getEdgeSource,
Collectors.groupingBy(
graph::getEdgeTarget,
Collectors.counting()
)
))
.entrySet().stream()
.forEach(startEntry ->
startEntry.getValue().entrySet().stream()
.forEach(endEntry ->
graph.setEdgeWeight(
graph.addEdge(startEntry.getKey(), endEntry.getKey()),
endEntry.getValue() / strains
)));
Upvotes: 3
Views: 366
Reputation: 28133
No, you have to have some sort of an intermediate data structure to accumulate counts. Depending on how your graph and edge classes are written, you could try to accumulate counts directly into the graph, but that would be less readable and more brittle.
Note that you can iterate over the intermediate map more concisely by using Map#forEach
:
.forEach((source, targetToCount) ->
targetToCount.forEach((target, count) ->
graph.setEdgeWeight(graph.addEdge(source, target), count/strains)
)
);
You can also collect the counts into Map<List<Node>, Long>
instead of Map<Node,Map<Node,Long>>
if you dislike the map-of-maps approach:
graphs.stream()
.map(AbstractBaseGraph::edgeSet)
.flatMap(Collection::stream)
.collect(groupingBy(
edge -> Arrays.asList(
graph.getEdgeSource(edge),
graph.getEdgeTarget(edge)
),
counting()
))
.forEach((nodes, count) ->
graph.setEdgeWeight(graph.addEdge(nodes.get(0), nodes.get(1)), count/strains)
);
Upvotes: 3