Reputation: 422
class Person {
String personName;
List<Skill> skills;
}
class Skill {
String skillName;
}
How to obtain a map of
E.g. John has skills painting, kungfu. James has cooking, karate, kungfu, Chris has painting, hiking
Output
painting -> John, Chris
kungfu -> John, James
cooking -> James
karate -> James
hiking -> Chris
What I have tried:
list.stream().collect(Collectors.groupingBy(e -> e.skills.stream(), Collectors.toSet()))
I know this does not work, because you cannot group by e.skills.stream().
list.stream().flatMap(e -> e.skills.stream()).collect(Collectors.groupingBy(e -> e.skillName, Collectors.toSet()));
It does group by skillName (but only Skill objects), however reference to Person is lost due to flatMap.
Upvotes: 1
Views: 207
Reputation: 40078
You can create Map.Entry object for every Skill_name->Person_name
combination, and then use Collectors.groupingBy for grouping the person names with skills
Map<String, List<String>> groupingBySkill = persons.stream()
.flatMap(p -> p.getSkills().stream().map(Skill::getSkillName)
.map(sk -> new AbstractMap.SimpleEntry<String, String>(sk, p.getPersonName())))
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
Upvotes: 1
Reputation: 29730
I think this would be easier to accomplish if you first converted your List<Person>
into a Stream<PersonNameSkill>
, where PersonNameSkill
represents a nominal tuple containing the Person
's name and a single Skill
that is attributed to them.
In Java 14, you can take advantage of record
to create this nominal tuple:
record PersonNameSkill(String personName, String skillName) {}
Now that this exists, you can write a solution (Java 8+):
list.stream().flatMap(person -> person.skills.stream()
.map(skill -> new PersonNameSkill(person.personName, skill.skillName)))
.collect(Collectors.groupingBy(PersonNameSkill::skillName,
Collectors.mapping(PersonNameSkill::personName, Collectors.toSet())));
If you're using an older version of Java, you can create PersonNameSkill
with:
public class PersonNameSkill {
private final String personName;
private final String skillName;
// Constructor, getters, equals, hashCode, etc.
}
Upvotes: 2