首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将列表流转换为单个容器

将列表流转换为单个容器
EN

Stack Overflow用户
提问于 2018-01-17 18:27:58
回答 4查看 530关注 0票数 14

考虑下面的WorkExperience类:

代码语言:javascript
复制
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 + "]";
    }
}     

假设我想按年按我的技能分组,这就是我们按年做groupBy的方法:

代码语言:javascript
复制
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())
        )
    );
}

groupBy正在返回:Map<Integer, Set<List<Skills>>>

但我需要的是:Map<Integer, Set<Skills>>

如何将列表流转换为单个容器?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2018-01-17 18:27:58

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

代码语言:javascript
复制
workExperienceList.stream().collect(Collectors.groupingBy(
                              WorkExperience::getYear, 
                              Collectors.flatMapping(workexp -> workexp.getSkill().stream(), 
                                             Collectors.toSet())));

API Note

flatMapping()收集器在多级还原(如groupingBy或partitioningBy的下游)中最有用。

票数 12
EN

Stack Overflow用户

发布于 2018-01-17 19:13:43

使用Java 8特性替代flatMapping的方法将是

代码语言:javascript
复制
Map<Integer, Set<Skills>> map = workExperienceList.stream()
    .collect(Collectors.toMap(
        WorkExperience::getYear,
        we -> new HashSet<>(we.getSkill()),
        (s1, s2)-> { s1.addAll(s2); return s1; }));

您可以对此进行一些优化

代码语言:javascript
复制
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; }
        }));
票数 14
EN

Stack Overflow用户

发布于 2018-01-18 18:39:55

实现所需的另一种方法是使用静态工厂方法Collector.of()实现自己的收集器。

代码语言:javascript
复制
Map<Integer, Set<Skills>> collect = workExperienceList.stream()
    .collect(Collector.of(
        HashMap::new,
        ( map, e ) -> map.computeIfAbsent(e.getYear(), k -> new HashSet<>()).addAll(e.getSkill()),
        ( left, right ) -> {
            right.forEach(( year, set ) -> left.computeIfAbsent(year, k -> new HashSet<>()).addAll(set));
            return left;
        })
    );

与其他答案相比,这是相当混乱和臃肿的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48307704

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档