有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java8按列表的各个元素分组

class Person {
    String personName;
    List<Skill> skills;
}

class Skill {
    String skillName;
}

如何获取地图

  1. 技能名和人名
  2. skillName和person对象

约翰有绘画、功夫等技能。詹姆斯有烹饪,空手道,功夫,克里斯有绘画,徒步旅行

输出

painting -> John, Chris
kungfu -> John, James
cooking -> James
karate -> James
hiking -> Chris

我所尝试的:

list.stream().collect(Collectors.groupingBy(e -> e.skills.stream(), Collectors.toSet()))

我知道这是行不通的,因为你不能按e.skills分组。流()

list.stream().flatMap(e -> e.skills.stream()).collect(Collectors.groupingBy(e -> e.skillName, Collectors.toSet()));

它确实按技能名称分组(但仅限于技能对象),但由于flatMap,对Person的引用丢失


共 (2) 个答案

  1. # 1 楼答案

    我认为,如果您首先将List<Person>转换为Stream<PersonNameSkill>,其中PersonNameSkill表示一个包含Person名称和一个归属于它们的Skill的标称元组,那么这将更容易实现

    在Java 14中,您可以利用record来创建这个标称元组:

    record PersonNameSkill(String personName, String skillName) {}
    

    既然有了它,您就可以编写一个解决方案(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())));
    

    如果您使用的是旧版本的Java,则可以使用以下工具创建PersonNameSkill

    public class PersonNameSkill {
        private final String personName;
        private final String skillName;
    
        // Constructor, getters, equals, hashCode, etc.
    }
    
  2. # 2 楼答案

    您可以为每个Skill_name->Person_name组合创建Map.Entry对象,然后使用Collectors.groupingBy将人名与技能分组

    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())));