Ann
Ann

Reputation: 247

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

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())
                        ));

Upvotes: 10

Views: 2927

Answers (5)

msucil
msucil

Reputation: 846

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())));

Upvotes: 0

Sergey Afinogenov
Sergey Afinogenov

Reputation: 2212

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;}));

Upvotes: 0

Yassin Hajaj
Yassin Hajaj

Reputation: 21975

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);

Upvotes: 4

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79075

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()));

Upvotes: 6

Eran
Eran

Reputation: 393821

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));

Upvotes: 14

Related Questions