Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grouping by and map value

I'm trying to do grouping by (to map) and then transform list of values to different list.

I have List of DistrictDocuments:

List<DistrictDocument> docs = new ArrayList<>(); 

Then I'm streaming over it and grouping it by city:

Map<String, List<DistrictDocument>> collect = docs.stream()                 .collect(Collectors.groupingBy(DistrictDocument::getCity)); 

I also have a method which takes DistrictDocument and creates Slugable out of it:

private Fizz createFizz(DistrictDocument doc) {     return new Fizz().name(doc.getName()).fizz(doc.getFizz()); } 

Is there a way to put that method into my stream above so I get Map<String, List<Fizz>> ? I tried adding 2nd argument to groupingBy but couldn't find a proper way and been always getting compilation errors.

Edit: What if my createFizz returns List<Fizz> ? Is there an option to flat this list in Collectors.mapping becasue I still want to have Map<String, List<Fizz>> instead of Map<String, List<List<Fizz>>>

like image 858
ohwelppp Avatar asked Feb 28 '18 12:02

ohwelppp


2 Answers

You need to chain a Collectors.mapping() collector to the Collectors.groupingBy() collector:

Map<String, List<Fizz>> collect =     docs.stream()         .collect(Collectors.groupingBy(DistrictDocument::getCity,                  Collectors.mapping(d->createFizz(d),Collectors.toList()))); 

If createFizz(d) would return a List<Fizz, you can flatten it using Java 9's Collectors.flatMapping:

Map<String, List<Fizz>> collect =     docs.stream()         .collect(Collectors.groupingBy(DistrictDocument::getCity,                  Collectors.flatMapping(d->createFizz(d).stream(),Collectors.toList()))); 

If you can't use Java 9, perhaps using Collectors.toMap will help:

Map<String, List<Fizz>> collect =     docs.stream()         .collect(Collectors.toMap(DistrictDocument::getCity,                                   d->createFizz(d),                                   (l1,l2)->{l1.addAll(l2);return l1;})); 
like image 56
Eran Avatar answered Sep 26 '22 03:09

Eran


In case you'd like to do a doubly nested grouping:

Let's say you have a collection of EducationData objects that contain School name, teacher name, and student name. But you want a nested map that looks like :

What you have

class EducationData {      String school;      String teacher;      String student;       // getters setters ... } 

What you want

Map<String, Map<String, List<String>>> desiredMapOfMpas ...  // which would look like this :  "East High School" : {      "Ms. Jackson" : ["Derek Shepherd", "Meredith Grey", ...],      "Mr. Teresa" : ["Eleanor Shellstrop", "Jason Mendoza", ...],      .... } 

How to Get There

import static java.util.stream.Collectors.*;  public doubleNestedGroup(List<EducationData> educations) {      Map<String, Map<String, List<String>>> nestedMap = educations.stream()         .collect(              groupingBy(                   EducationData::getSchool,                   groupingBy(                        EducationData::getTeacher,                        mapping(                             EducationData::getStudent,                             toList()                        )                   )               )         ); } 
like image 26
Fabian Avatar answered Sep 22 '22 03:09

Fabian