将列表流转换为单个Container

Nir*_*ane 14 java java-8 java-stream java-9

考虑以下WorkExperience课程:

public class WorkExperience {
    private int year;
    private List<Skills> skill;

    public WorkExperience(int year, List<Skills> skill) {
        this.year = year;
        this.skill = skill;
    }   
    //getter setter         
}

public class Skills {
    private String skills;

    public Skills(String skills) {
        this.skills = skills;
    }

    @Override
    public String toString() {
        return "Skills [skills=" + skills + "]";
    }
}     
Run Code Online (Sandbox Code Playgroud)

假设我希望按年份按照我的技能进行分组,这就是我们groupBy今年的表现:

public static void main(String[] args) {

    List<Skills> skillSet1 = new  ArrayList<>();
    skillSet1.add(new Skills("Skill-1"));
    skillSet1.add(new Skills("Skill-2"));
    skillSet1.add(new Skills("Skill-3"));

    List<Skills> skillSet2 = new  ArrayList<>();
    skillSet2.add(new Skills("Skill-1"));
    skillSet2.add(new Skills("Skill-4"));
    skillSet2.add(new Skills("Skill-2"));


    List<Skills> skillSet3 = new  ArrayList<>();
    skillSet3.add(new Skills("Skill-1"));
    skillSet3.add(new Skills("Skill-9"));
    skillSet3.add(new Skills("Skill-2"));

    List<WorkExperience> workExperienceList = new ArrayList<>();
    workExperienceList.add(new WorkExperience(2017,skillSet1));
    workExperienceList.add(new WorkExperience(2017,skillSet2));
    workExperienceList.add(new WorkExperience(2018,skillSet3));

    Map<Integer, Set<List<Skills>>> collect = workExperienceList.stream().collect(
        Collectors.groupingBy(
            WorkExperience::getYear,
            Collectors.mapping(WorkExperience::getSkill, Collectors.toSet())
        )
    );
}
Run Code Online (Sandbox Code Playgroud)

groupBy正在回归:Map<Integer, Set<List<Skills>>>
但我需要的是:Map<Integer, Set<Skills>>

如何将List流转换为单个Container?

Hol*_*ger 14

flatMapping只使用Java 8功能的替代方案

Map<Integer, Set<Skills>> map = workExperienceList.stream()
    .collect(Collectors.toMap(
        WorkExperience::getYear,
        we -> new HashSet<>(we.getSkill()),
        (s1, s2)-> { s1.addAll(s2); return s1; }));
Run Code Online (Sandbox Code Playgroud)

你可以稍微优化一下

Map<Integer, Set<Skills>> map = workExperienceList.stream()
    .collect(Collectors.toMap(
        WorkExperience::getYear,
        we -> new HashSet<>(we.getSkill()),
        (s1, s2) -> {
            if(s1.size() > s2.size()) { s1.addAll(s2); return s1; }
            else { s2.addAll(s1); return s2; }
        }));
Run Code Online (Sandbox Code Playgroud)

  • 甚至[在您的答案中]建议的`flatMapping`方法实现(/sf/answers/2739173461/)。 (2认同)

Nir*_*ane 12

我们可以使用Java-9中Collectors.flatMapping 添加的收集器.通过使用flatMapping,我们可以将中间列表展平为单个容器. flatMapping可以在原始流的元素可转换为流的情况下使用.

workExperienceList.stream().collect(Collectors.groupingBy(
                              WorkExperience::getYear, 
                              Collectors.flatMapping(workexp -> workexp.getSkill().stream(), 
                                             Collectors.toSet())));
Run Code Online (Sandbox Code Playgroud)

API注意:

flatMapping()收集器在多级缩减中使用时非常有用,例如groupingBy或partitioningBy的下游.