Java 坚持使用lambda表达式和映射

Java 坚持使用lambda表达式和映射,java,lambda,java-8,java-stream,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 M

我有
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;
    }
}
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())));
    }
}
App
类中,
PeoplePerSkill
方法需要返回每个技能的
人名集。这意味着一项技能可以被许多人拥有

我坚持使用
groupingBy(p->p………..)
我就是不能得到skill名字的
字符串,我尝试了很多方法,但是事情变得很奇怪:(


顺便说一下,目前我的代码返回
Map

您可以通过平面映射来完成,尽管它看起来可能不是很漂亮:

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())));
}
在内部,它几乎是一样的,只是语法上的糖


更新:似乎我原来的解决方案是错误的:它返回map
person\u name->[skills]
,但如果我正确理解了OP,他想要map
skill->[person\u name]
。答案已编辑。

我不确定流是否会让您的生活更轻松。在我看来,这段代码更容易阅读,更干净

public Map<String, Set<String>> peoplePerSkill() {

    Map<String, Set<String>> map = new HashMap<>();

    for (Person person : people) {
        for (String skill : person.getSkills().keySet()) {
            map.putIfAbsent(skill, new HashSet<>());
            map.get(skill).add(person.getName());
        }
    }

    return map;
}
公共地图peoplePerSkill(){
Map Map=newhashmap();
用于(人:人){
for(字符串技能:person.getSkills().keySet()){
map.putIfAbsent(skill,new HashSet());
map.get(skill.add(person.getName());
}
}
返回图;
}
你也可以“简化”

map.putIfAbsent(skill,new HashSet());
map.get(skill.add(person.getName());

map.computeIfAbsent(skill,k->newhashset()).add(person.getName());

< /代码> 如果您可以在代码中使用外部库,您可能需要考虑使用“A”代替“代码> map ”。不幸的是,使用<代码> MultMAP的解决方案将需要更多的样板,因为JDK没有正式支持它,但是它应该导致一个“更干净”的解决方案:

  public static void main(String[] args) {
    Person larry = new Person("larry");
    larry.getSkills().put("programming", 0);
    larry.getSkills().put("cooking", 0);

    Person nishka = new Person("nishka");
    nishka.getSkills().put("programming", 0);
    nishka.getSkills().put("cooking", 0);

    Person mitul = new Person("mitul");
    mitul.getSkills().put("running", 0);
    mitul.getSkills().put("cooking", 0);

    Person rebecca = new Person("rebecca");
    rebecca.getSkills().put("running", 0);
    rebecca.getSkills().put("programming", 0);

    List<Person> people = Arrays.asList(larry, nishka, mitul, rebecca);

    Multimap<String, String> peopleBySkills = people.stream().collect(
        collectingAndThen(toMap(Person::getName, p -> p.getSkills().keySet()),
            CollectingMultimap.<String, String, Set<String>> toMultimap()
                .andThen(invert())));
    System.out.println(peopleBySkills);
  }

  private static <K, V, I extends Iterable<V>> Function<Map<K, I>, Multimap<K, V>> toMultimap() {
    return m -> {
      Multimap<K, V> map = ArrayListMultimap.create();
      m.entrySet().forEach(e -> map.putAll(e.getKey(), e.getValue()));
      return map;
    };
  }

  private static <K, V> Function<Multimap<K, V>, Multimap<V, K>> invert() {
    return m -> {
      return Multimaps.invertFrom(m, ArrayListMultimap.create());
    };
  }
请注意我是如何向
toMultimap()
提供泛型参数的。Java8具有更好的泛型推理,但它的性能更好

您需要显式地提供泛型参数,或者将局部变量
函数声明为multimap
,以便编译器正确地推断类型参数

map.putIfAbsent(skill, new HashSet<>());
map.get(skill).add(person.getName());
map.computeIfAbsent(skill, k -> new HashSet<>()).add(person.getName());
  public static void main(String[] args) {
    Person larry = new Person("larry");
    larry.getSkills().put("programming", 0);
    larry.getSkills().put("cooking", 0);

    Person nishka = new Person("nishka");
    nishka.getSkills().put("programming", 0);
    nishka.getSkills().put("cooking", 0);

    Person mitul = new Person("mitul");
    mitul.getSkills().put("running", 0);
    mitul.getSkills().put("cooking", 0);

    Person rebecca = new Person("rebecca");
    rebecca.getSkills().put("running", 0);
    rebecca.getSkills().put("programming", 0);

    List<Person> people = Arrays.asList(larry, nishka, mitul, rebecca);

    Multimap<String, String> peopleBySkills = people.stream().collect(
        collectingAndThen(toMap(Person::getName, p -> p.getSkills().keySet()),
            CollectingMultimap.<String, String, Set<String>> toMultimap()
                .andThen(invert())));
    System.out.println(peopleBySkills);
  }

  private static <K, V, I extends Iterable<V>> Function<Map<K, I>, Multimap<K, V>> toMultimap() {
    return m -> {
      Multimap<K, V> map = ArrayListMultimap.create();
      m.entrySet().forEach(e -> map.putAll(e.getKey(), e.getValue()));
      return map;
    };
  }

  private static <K, V> Function<Multimap<K, V>, Multimap<V, K>> invert() {
    return m -> {
      return Multimaps.invertFrom(m, ArrayListMultimap.create());
    };
  }
{running=[mitul, rebecca], cooking=[nishka, larry, mitul], programming=[nishka, larry, rebecca]}