I need to concat data if duplicates will occur. But can't to do it.
Is it possible to convert String to Object in that case or join that data by another expression?
I have a problem there: (a, b) -> a + ", " + b
as
Bad return type in lambda expression String cannot be converted to Subject
Map<Student, Subject> result = markList
.stream()
.collect(Collectors.toMap(
Mark::getStudent,
Mark::getSubject,
(a, b) -> a + ", " + b));
result.forEach((student, subject) ->
System.out.printf("%s %s : %s ", student.getFirstName(),
student.getLastName(), subject.getName()));
Here is markList:
List<Mark> markList = new ArrayList<>();
markList.add(new Mark(student_1, subject_1, 1));
markList.add(new Mark(student_1, subject_2, 2));
markList.add(new Mark(student_2, subject_1, 1));
And expect to get joined Subject data in case duplicates would found
Expected Output:
[ student_1
with subject_1
, subject_2
and
student_2
with subject_1
]:
John McDonald: Mathematics, Astronomy
Kira Wild: Mathematics
=====================================================
But
this code works without duplicates as: (a, b) -> a
Output:
John McDonald: Mathematics
Kira Wild: Mathematics
First things first, (a, b) -> a + ", " + b)
will not compile simply because the returned value must be a Subject
rather than a String
, I believe you have eventually figured this out given your latest edit states the code is now working without duplicates when using the (a, b) -> a
merge function.
The reason why you're not getting the expected result given your latest update is that you're using the merge function (a, b) -> a
meaning "if two given Subjects have the same Student then keep the first student and discard the second".
Instead what you want to do is somehow maintain both students so in essence, you'll have a Map<Student, List<Subject>>
.
This can be done as:
Map<Student, List<Subject>> result = markList
.stream()
.collect(Collectors.toMap(
Mark::getStudent,
v -> new ArrayList<>(singletonList(v.getSubject())),
(a, b) -> {a.addAll(b); return a;}));
Actually this is better done via groupingBy
with a mapping
as downstream collector:
Map<Student, List<Subject>> resultSet = markList.stream()
.collect(groupingBy(Mark::getStudent,
mapping(Mark::getSubject, toList())));
and finally you can test the results with:
resultSet.forEach((student, subjects) ->
System.out.printf("%s %s : %s ", student.getFirstName(), student.getLastName(),
subjects.stream().map(Subject::getName).collect(joining(", "))));