【问题标题】:Stream groupingBy a list of enum types流分组按枚举类型列表
【发布时间】:2019-10-20 18:12:45
【问题描述】:

我有一个产品类:

class Product {
    String name;
    List<Group> group;
    //more fields, getters, setters
    public Product(String name, Group... group) {
        this.name = name;
        this.group = Arrays.asList(group);
    }
}

其中 Group 是一个枚举

public enum Group {
    LEISURE,
    SPORT,
    FORMALATTIRE,
    BABY,
    MATERNITY
    //...
}

从我想创建一个Map&lt;Group,List&lt;Product&gt;&gt;的产品列表中@

示例输入:

List<Product> productList = new ArrayList<>();

productList.add(new Product("A", Group.BABY, Group.MATERNITY));
productList.add(new Product("B", Group.BABY, Group.LEISURE, Group.SPORT));
productList.add(new Product("C", Group.SPORT, Group.LEISURE));
productList.add(new Product("D", Group.LEISURE, Group.SPORT, Group.FORMALATTIRE));
productList.add(new Product("E", Group.SPORT, Group.LEISURE));
productList.add(new Product("F", Group.FORMALATTIRE, Group.LEISURE));

如果组是一个单一的字段,就像我可以做的名字一样:

productList.stream().collect(Collectors.groupingBy(Product::getName));

我如何使用List&lt;Group&gt; 做到这一点?

预期结果如下所示,其中对于 productList 中存在的每个组,映射到在其字段中具有该组的产品列表 group

{MATERNITY=[A], FORMALATTIRE=[D, F], LEISURE=[B, C, D, E, F], SPORT=[B, C, D, E], BABY=[A, B]}

【问题讨论】:

    标签: java java-stream grouping


    【解决方案1】:

    您可以将每个Product中的flatMap分组到产品的name,然后通过Group映射对应的names作为值进行分组。如:

    Map<Group, List<String>> groupToNameMapping = productList.stream()
            .flatMap(product -> product.getGroup().stream()
                    .map(group -> new AbstractMap.SimpleEntry<>(group, product.getName())))
            .collect(Collectors.groupingBy(Map.Entry::getKey,
                    Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
    

    或者要获得组到产品列表的映射,您可以制定相同的公式:

    Map<Group, List<Product>> groupToProductMapping = productList.stream()
            .flatMap(product -> product.getGroup().stream()
                    .map(group -> new AbstractMap.SimpleEntry<>(group, product)))
            .collect(Collectors.groupingBy(Map.Entry::getKey,
                    Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
    

    【讨论】:

    • 已经尝试过您的方法,但得到错误不兼容类型:推理变量 U 具有不兼容的边界下限:产品,T#2,对象下限:字符串
    • @nopens 编辑了答案。它将解决问题并提供您正在寻找的内容。
    • 非常感谢。第二种方法正是我想要的。
    【解决方案2】:

    您可以使用flatMap 创建Entry&lt;Group,String&gt; 流,然后使用Collectors.mapping 将它们收集到Map&lt;Group, List&lt;String&gt;&gt;

    productList.stream()
                   .flatMap(p->p.getGroup()
                                .stream()
                                .map(g->new AbstractMap.SimpleEntry<>(g,p.getName())))   // or from jdk 9 you can use Map.entry(g, p.getName());
                   .collect(Collectors.groupingBy(Map.Entry::getKey, 
                           Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
    

    【讨论】:

    • 条目的类型也是可以推断的,所以可以使用AbstractMap.SimpleEntry&lt;&gt;
    • 已绑定您的方法但收到错误incompatible types: inference variable U has incompatible bounds lower bounds: Product,T#2,Object lower bounds: String
    • 没关系。我的错。我期待Map&lt;Group,List&lt;Product&gt;&gt;。我已将 p.getName 更改为 p 并且它按预期工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-15
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    • 1970-01-01
    相关资源
    最近更新 更多