I have a list of maps as below.
And I want to group the entry sets by key, if a key non exist, fill 0 instead.
List<Map<String, Double>> props = Lists.newArrayList();
Map<String, Double> m1 = Maps.newHashMap();
m1.put("a", 0.1);
m1.put("b", 0.5);
m1.put("c", 0.6);
Map<String, Double> m2 = Maps.newHashMap();
m2.put("a", 0.3);
m2.put("d", 0.1);
Map<String, Double> m3 = Maps.newHashMap();
m3.put("a", 0.2);
props.add(m1); props.add(m2); props.add(m3);
Expected result:
{a=[0.1, 0.3, 0.2], b=[0.5, 0, 0], c=[0.6,0,0], d=[0,0.1,0]}
I got an idea:
Any good ideas?
It can be done in single line lamda and stream except the case fill every map of missing keys with value 0
Map<String, List<Double>> collect = Stream.of(m1, m2, m3)
.flatMap(map -> map.entrySet().stream())
.collect(groupingBy(
Map.Entry::getKey,
mapping(Map.Entry::getValue, toList()))
);
System.out.println(collect);
And this will produce the output as
{a=[0.1, 0.3, 0.2], b=[0.5], c=[0.6], d=[0.1]}
Here static factory methods Collectors.groupingBy() is used to group the concatenated Entries of all maps by the Key (classifier) and mapping method (collector).
If its the obvious case you must to fill every map of missing keys with value 0 then there is several way of doing that. One that @abhi stated in other answer. Along with his idea I would like to do that this way
Set<String> allKeys = Sets.newHashSet();
props.forEach(prop -> allKeys.addAll(prop.keySet()));
allKeys.forEach(k -> props.forEach(m -> m.putIfAbsent(k, 0.0)));
Infact this will modify your original maps with allKeys having 0 as value ifNotPresent. If this modification causes you problem you can prefer to copy your maps to have separate collections.
This will ensure your desired output
{a=[0.1, 0.3, 0.2], b=[0.5, 0.0, 0.0], c=[0.6, 0.0, 0.0], d=[0.0, 0.1, 0.0]}
Note: You can find this article interesting about Grouping using Java 8 streams
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With