Convert a list of objects to Map<Long, List<>> using streams

Viewed 896

I want to convert a list of Student objects to Map<Long, List<>> using streams.

List<Student> list = new ArrayList<Student>();
list.add(new Student("1", "test 1"));
list.add(new Student("3", "test 1"));
list.add(new Student("3", "test 3"));

I want the final outcome in the following way:

Map

Key: 1

Value List: Student("1", "test 1")

Key: 3

Value List: Student("3", "test 1"), Student("3", "test 3")

I tried the following code, but it is reinitializing the Student objects. Can anyone help me fix the below code?

Map<Long, List<Student>> map = list.stream()
                        .collect(Collectors.groupingBy(
                                Student::getId,
                                Collectors.mapping(Student::new, Collectors.toList())
                        ));
5 Answers

You don't need to chain the mapping collector. The single argument groupingBy will give you a Map<Long, List<Student>> by default.

Map<Long, List<Student>> map = 
    list.stream()
        .collect(Collectors.groupingBy(Student::getId));

The answer by Eran is spot-on. Just to add to that, you can also use a Supplier e.g.

Map<Long, List<Student>> map = 
    list.stream()
        .collect(Collectors.groupingBy(Student::getId, TreeMap::new, Collectors.toList()));

For these kind of easy use cases, I prefer to look at Eclipse Collections instead of relying on the overhead of creating a Stream.

The result is the same, it gives you a java.util.Map and I find the syntax more concise

MutableList<Student> list = Lists.mutable.of();
list.add(new Student("1", "test 1"));
list.add(new Student("3", "test 1"));
list.add(new Student("3", "test 3"));

Map<String, List<Student>> map = list.groupBy(Student::getId).toMap(ArrayList::new);

As alternative of groupingBy using toMap:

Map<Long, List<Student>> result = list.stream()
                                      .collect(Collectors.toMap(Student::getId,
                                                                s-> { List<Student> l = new ArrayList<>();
                                                                      l.add(s);
                                                                      return l;
                                                                    },
                                                                    (l1,l2)-> { l1.addAll(l2); 
                                                                                return l1;}));

then answer provided by @Eran is straight forward but if you want to change the data type in this context String to Long then you can use lamda expression to convert String to Long

Map<Long, List<Student>> map = 
    list.stream()
        .collect(Collectors.groupingBy(s ->Long.parseLong(s.getId())));
Related