Search code examples
javajava-8java-streamcollectorsgroupingby

Java 8 stream grouping a List<Map<>> by the same <Key, Value> to a new List<Map<>>


I have a List<Map<String,String>> such as:

Map<String, String> m1 = new HashMap<>();
m1.put("date", "2020.1.5");
m1.put("B", "10");

Map<String, String> m2 = new HashMap<>();
m2.put("date", "2020.1.5");
m2.put("A", "20");

Map<String, String> m3 = new HashMap<>();
m3.put("date", "2020.1.6");
m3.put("A", "30");

Map<String, String> m4 = new HashMap<>();
m4.put("date", "2020.1.7");
m4.put("C", "30");

List<Map<String, String>> before = new ArrayList<>();
before.add(m1);
before.add(m2);
before.add(m3);
before.add(m4);

My expect result is to generate a new List map, which is grouped by date , and all the entry set in the same date would be put together, like:

[{"A":"20","B":"10","date":"2020.1.5"},{"A":"30","date":"2020.1.6"},{"C":"30","date":"2020.1.7"}]

I tried with the following method, but always not my expect result.

stream().flatmap().collect(Collectors.groupingBy())

Some Additional Comments for this problem:

I worked this out with for LOOP, but the application hangs when the list size is about 50000, so I seek a better performant way to do this. Java 8 stream flat map is a perhaps way as far as I know. So the key point is not only to remap this but also with the most performant way to do this.


Solution

  • You can do this way using groupingBy and Collector.of

    List<Map<String, String>> list = new ArrayList<>(before.stream()
            .collect(Collectors.groupingBy(
                    k -> k.get("date"),
                    Collector.of( HashMap<String,String>::new,
                            (m,e)-> m.putAll(e),
                            (map1,map2)->{ map1.putAll(map2); return map1;}
                    ))).values());
    

    Here, first use Collectors.groupingBy to group by date. Then define custom collector using Collector.of to collect List<Map<String, String>> into Map<String, String>. After create list using map values.

    And using Collectors.flatMapping from Java 9

    List<Map<String, String>> list = new ArrayList<>(before.stream()
            .collect(Collectors.groupingBy(
                    k -> k.get("date"),
                    Collectors.flatMapping(m -> m.entrySet().stream(), 
                        Collectors.toMap(k -> k.getKey(), v -> v.getValue(), (a,b) -> a))))
                   .values());