按单个元素分组的Java 8列表

问题描述 投票:1回答:2
class Person {
    String personName;
    List<Skill> skills;
}

class Skill {
    String skillName;
}

如何获得地图

  1. 技能名称和人名
  2. 技能名称和人员对象

如:约翰有绘画、功夫等技能。詹姆士有烹饪、空手道、功夫,克里斯有绘画、远足。

产量

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.stream()分组。

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

它确实可以通过技能名称进行分组(但只是技能对象),但是由于flatMap的原因,失去了对Person的引用。

java java-stream
2个回答
2
投票

我想如果你先将你的 "技能 "和 "人名 "转换为 "人名",会更容易实现。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.
}

1
投票

你可以创建 地图.条目 对象的每一个 Skill_name->Person_name 组合,然后用 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())));
© www.soinside.com 2019 - 2024. All rights reserved.