Ankur Singhal
Ankur Singhal

Reputation: 26077

Stream - Nested Collection - Convert to Map

Let's say i have 2 classes.

Course Class

public class Course {
    private int id;
    private String name;
}

Student Class

public class Student {
    private int id;
    private String name;
    private List<Course> courses;
}

I have List<Student> and each Student is enrolled in multiple courses.

I need to filter out results using Java 8 stream API's as following.

Map<courseId, List<Student>> 

I have tried below, but no success:

1st Approach

Map<Integer, List<Student>> courseStudentMap = studentList.stream()
    .collect(Collectors.groupingBy(
        student -> student.getCourses().stream()
            .collect(Collectors.groupingBy(Course::getId))));

2nd Approach

Map<Integer, List<Student>> courseStudentMap = studentList.stream()
    .filter(student -> student.getCourses().stream()
        .collect(Collectors.groupingBy(
            Course::getId, Collectors.mapping(Student::student, Collectors.toList()))));

Upvotes: 5

Views: 133

Answers (2)

Eran
Eran

Reputation: 394126

Something like this should work (where SimpleEntry is a class that implements Map.Entry<Integer,Student>:

Map<Integer, List<Student>> courseStudentMap =
    studentList.stream()
               .flatMap(s -> s.getCourses()
                              .stream()
                              .map(c -> new SimpleEntry<>(c.getId(),s)))
               .collect(Collectors.groupingBy(Map.Entry::getKey,
                        Collectors.mapping(Map.Entry::getValue,
                                           Collectors.toList())));

The idea is to first transform the Stream<Student> to a Stream of all the pairs of course IDs and Students. Once you got that Stream, you can use groupingBy to obtain the desired output Map.

Upvotes: 4

Eugene
Eugene

Reputation: 121048

 Map<Integer, List<Student>> result = studentsList
            .stream()
            .flatMap(x -> x.getCourses().stream().map(y -> new SimpleEntry<>(x, y.getId())))
            .collect(Collectors.groupingBy(
                    Entry::getValue,
                    Collectors.mapping(Entry::getKey, Collectors.toList())));

Upvotes: 4

Related Questions