坚持使用lambda表达式和Map

Fen*_*eng 7 java lambda java-8 java-stream

Person上课了:

import java.util.*;
public class Person {
    private String name;
    Map<String,Integer> Skills=new HashMap<>(); // skill name(String) and level(int)

    public String getName(){
        return this.name;
    }
    public Map<String,Integer> getSkills(){
        return this.Skills;
    }
}
Run Code Online (Sandbox Code Playgroud)

App班级:

import java.util.*;
import java.util.Map.Entry;
import static java.util.stream.Collectors.*;
import static java.util.Comparator.*;
public class App {
    private List<Person> people=new ArrayList<>(); // the people in the company

    public Map<String,Set<String>> PeoplePerSkill(){
        return this.people.stream().collect(groupingBy(p-> p.getSkills().keySet() //<-get  
                                                                           //^problem here
                                  ,mapping(Person::getName,toSet())));
    }
}
Run Code Online (Sandbox Code Playgroud)

App该类中,该PeoplePerSkill方法需要返回Set每个技能的人名.这意味着许多人可以拥有一项技能.

我坚持groupingBy(p->p..........., )我只是不能得到String技能的名字,我尝试了很多方法,但事情变得陌生:(.

顺便说一句,目前我的代码返回 Map<Object, Set<String>>

Tag*_*eev 6

你可以通过平面映射来做到这一点,虽然它可能看起来不是很漂亮:

public Map<String,Set<String>> PeoplePerSkill(){
    return this.people.stream()
        .<Entry<String, String>>flatMap(p -> 
            p.getSkills().keySet()
                .stream()
                .map(s -> new AbstractMap.SimpleEntry<>(s, p.getName())))
        .collect(groupingBy(Entry::getKey, mapping(Entry::getValue, toSet())));
}
Run Code Online (Sandbox Code Playgroud)

这里flatMap创建了一对对象流(skill, person name),它们以与您非常相似的方式收集.我正在使用AbstractMap.SimpleEntry该类代表该对,您可以使用其他东西.

使用我的StreamEx库可以更好地解决此任务:

return StreamEx.of(this.people)
        .mapToEntry(p -> p.getSkills().keySet(), Person::getName)
        .flatMapKeys(Set::stream)
        .grouping(toSet());
Run Code Online (Sandbox Code Playgroud)

在内部它几乎是相同的,只是语法糖.

更新:似乎我的原始解决方案是错误的:它返回了地图person_name -> [skills],但如果我正确理解OP,他想要地图skill -> [person_names].答案编辑.