Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java8 a list of map reduce by key

Tags:

java

java-8

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:

  1. find all distinct keys
  2. fill every map of missing keys with value 0
  3. groupby key, values mapping to a list

Any good ideas?

like image 549
slee Avatar asked Oct 27 '25 03:10

slee


1 Answers

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

like image 100
Shafin Mahmud Avatar answered Oct 28 '25 17:10

Shafin Mahmud



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!