6

I have Map<Integer,Doctor> docLib=new HashMap<>(); to save class of Doctor.

Class Doctor has methods:getSpecialization() return a String,
getPatients() to return a collection of class Person.

In the main method, I type:

public Map<String,Set<Person>> getPatientsPerSpecialization(){
 Map<String,Set<Person>> res=this.docLib.entrySet().stream().
 map(d->d.getValue()).
 collect(groupingBy(d->d.getSpecialization(),
 d.getPatients()) //error
 );
 return res;
}

As you can see, I have problem with groupingBy,I try to send the same value d to the method, but it's wrong. How to solve this?

Eran
395k57 gold badges726 silver badges793 bronze badges
asked Jun 20, 2015 at 5:15
1
  • It seems like you got some good answers to this question, but in the future, please include the exact error message you receive, and descriptions of any other behavior that differs from your expected behavior. Saying "it's wrong" doesn't say much about your issue. Commented Jun 24, 2015 at 17:23

2 Answers 2

5

You need a second Collector for that mapping :

public Map<String,Set<Person>> getPatientsPerSpecialization(){
 return this.docLib
 .values()
 .stream()
 .collect(Colectors.groupingBy(Doctor::getSpecialization,
 Collectors.mapping(Doctor::getPatients,toSet()))
 );
}

EDIT:

I think my original answer may be wrong (it's hard to say without being able to test it). Since Doctor::getPatients returns a Collection, I think my code may return a Map<String,Set<Collection<Person>>> instead of the desired Map<String,Set<Person>>.

The easiest way to overcome that is to iterate over that Map again to produce the desired Map :

public Map<String,Set<Person>> getPatientsPerSpecialization(){
 return this.docLib
 .values()
 .stream()
 .collect(Colectors.groupingBy(Doctor::getSpecialization,
 Collectors.mapping(Doctor::getPatients,toSet()))
 )
 .entrySet()
 .stream()
 .collect (Collectors.toMap (e -> e.getKey(),
 e -> e.getValue().stream().flatMap(c -> c.stream()).collect(Collectors.toSet()))
 );
}

Perhaps there's a way to get the same result with a single Stream pipeline, but I can't see it right now.

answered Jun 20, 2015 at 5:18
Sign up to request clarification or add additional context in comments.

3 Comments

Instead of docLib.entrySet().stream().map(d->d.getValue()) you can write docLib.values().stream().
@Holger cool :). I was wondering if I was missing some way of doing this flat mapping in Java 8. I guess I wasn't.
2

Instead of groupingBy, you could use toMap:

public Map<String, Set<Person>> getPatientsPerSpecialization() {
 return docLib.values()
 .stream()
 .collect(toMap(Doctor::getSpecialization,
 d -> new HashSet<>(d.getPatients()),
 (p1, p2) -> Stream.concat(p1.stream(), p2.stream()).collect(toSet())));
}

What it does is that it groups the doctors per specialization and map each one to a set of the patients it has (so a Map<String, Set<Person>>).

If, when collecting the data from the pipeline, you encounter a doctor with a specialization that is already stored as a key in the map, you use the merge function to produce a new set of values with both sets (the set that is already stored as a value for the key, and the set that you want to associate with the key).

answered Jun 20, 2015 at 5:50

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.