I am new to java and lambda, I want to find the sum and average of values in a map of maps.
My object is like Map<String, Map<String, Double>> browserData;
Data is of the format
<Chrome, <UK, 2.90>>
<Chrome, <US, 5.20>>
<Chrome, <EU, -0.25>>
<IE, <UK, 0.1>>
<IE, <US, -.20>>
<IE, <EU, 0.00>>
<FF, <UK, 0.90>>
<FF, <US, 1.20>>
<FF, <EU, 1.25>>
The final result needs to be two maps, 1 for sum and another for average
map1 = <CountryName, SumValue>
map2 = <CountryName, AverageValue>
So the result of the above example it would be
map1 = <UK, 3.9>
<US, 6.2>
<EU, 1>
map2 = <UK, 1.3>
<US, 2.07>
<EU, 0.33>
How can I achieve this?
The idea is to stream each of the entries of the inner maps and apply the appropriate collector to calculate the values you need:
Map<String, DoubleSummaryStatistics> stats = browserData.values().stream()
.flatMap(m -> m.entrySet().stream()) //Stream the inner maps' entrySets
.collect(groupingBy(Entry::getKey, summarizingDouble(Entry::getValue)));
DoubleSummaryStatistics ds = stats.getOrDefault("EU", new DoubleSummaryStatistics());
System.out.println("sumEu = " + ds.getSum());
System.out.println("avgEu = " + ds.getAverage());
If you do need the individual sum and average maps, you can create them from the summary map:
Map<String, Double> map1 = stats.entrySet().stream()
.collect(toMap(Entry::getKey, e -> e.getValue().getSum()));
Map<String, Double> map2 = stats.entrySet().stream()
.collect(toMap(Entry::getKey, e -> e.getValue().getAverage()));
note: I have used the following static imports:
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.summarizingDouble;
import static java.util.stream.Collectors.toMap;