10

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())
                        ));
Lii
  • 11,553
  • 8
  • 64
  • 88
Ann
  • 217
  • 1
  • 9

5 Answers5

14

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));
Eran
  • 387,369
  • 54
  • 702
  • 768
6

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()));
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
4

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);
Yassin Hajaj
  • 21,337
  • 9
  • 51
  • 89
  • 1
    This indeed looks very lucid. I had heard of this API but have seen it the first time in action through your answer. – Arvind Kumar Avinash Apr 28 '21 at 20:53
  • 1
    @ArvindKumarAvinash thanks, I think I'll answer more and more adding examples from this library, it is very good – Yassin Hajaj Apr 28 '21 at 20:54
  • After writing [this answer](https://stackoverflow.com/a/67372448/10819573), I just thought to check with you whether it can be further simplified using Eclipse Collections API. If yes, please post the same for the benefit of future visitors. – Arvind Kumar Avinash May 03 '21 at 16:38
  • 1
    Hi @ArvindKumarAvinash sure thanks for thinking about me, I'll check right away :) – Yassin Hajaj May 03 '21 at 16:43
0

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;}));
Sergey Afinogenov
  • 2,137
  • 4
  • 13
0

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())));
msucil
  • 806
  • 1
  • 8
  • 15