如何将pojo ID的地图收集到pojo上集合的属性集

时间:2020-08-07 16:03:33

标签: java java-8 java-stream

我正在尝试使用流将pojo的地图映射到由pojo上的属性公开的一组项目。我知道还不清楚,所以我将展示如何在没有流的情况下完成它。

我拥有和列举产品类别,并列出具有此类产品的产品清单和商店清单

public enum Category {
    FRUIT, VEGITABLE, MEAT;
}

public enum Product {
    APPLE ( Category.FRUIT ),
    PEAR ( Category.FRUIT ),
    BANANA ( Category.FRUIT ),
    CARROT ( Category.VEGITABLE ),
    POTATO ( Category.VEGITABLE ),
    CABBAGE ( Category.VEGITABLE ),
    MINCE ( Category.MEAT ),
    CHOP ( Category.MEAT ),
    STEAK ( Category.MEAT );

    private final Category category;

    Product( Category category ) {
        this.category = category;
    }

    public String value() {
        return name();
    }

    public static Product fromValue( String v ) {
        return valueOf( v );
    }

    public Category getCategory() {
        return this.category;
    }
}

public class Shop {

    private long id;
    private String name;
    private EnumSet<Product> products;

    public Shop( long id, String name, Collection<Product> products ) {
        this.id = id;
        this.name = name;
        this.products = ofNullable( products ).map( EnumSet::copyOf ).orElse( null );
    }
}

我已经建立了一种创建一些虚拟数据的方法...

public static List<Shop> getListOfShops() {
        Shop shop1 = new Shop( 1, "Green Grocer", EnumSet.of( Product.APPLE, Product.BANANA, Product.CARROT, Product.CABBAGE ) );
        Shop shop2 = new Shop( 2, "Supermarket", EnumSet.of( Product.APPLE, Product.BANANA
            , Product.CARROT, Product.CABBAGE, Product.CHOP, Product.MINCE ) );
        Shop shop3 = new Shop( 3, "Butcher", EnumSet.of( Product.STEAK ) );

        return Arrays.asList( shop1, shop2, shop3 );
    }

我要创建商店类别地图

Map<String, EnumSet<Category>> shopCategories = new HashMap<>();

将具有这样的内容

{屠夫= [肉类],超市= [水果,蔬菜,肉类],绿色 Grocer = [水果,蔬菜]}

我已经通过一些基本的循环实现了这些,我希望自己足够聪明,可以将其转换为流

public static Map<String, EnumSet<Category>> getCategories( List<Shop> shops ) {

    Map<String, EnumSet<Category>> shopCategories = new HashMap<>();

    for ( Shop s : shops ) {
        Set<Category> cats = new HashSet<Category>();
        for ( Product p : s.getProducts() ) {
            cats.add( p.getCategory() );
        }
        shopCategories.put ( s.getName(), EnumSet.copyOf (cats) );
    }

    return shopCategories;
}

我有一个模糊的想法,如何将其转换为商店地图,并以收藏家为终端操作的产品。类似于

shops.stream().collect( Collectors.toMap ( s -> s::getName ,
    PaymentProductWithCapabilities::getProducts ) );

我正在努力寻找一个切入点,以了解如何继续映射类别?谁能指出我正确的方向?

2 个答案:

答案 0 :(得分:3)

您可以使用add_done_callback()中的Map,将正在经营的商店的产品转换为期望的valueMapper的价值,类似于您的迭代风格,如下所示:

Collectors.toMap

准确地说,如果为两个商店找到了相同的return shops.stream() .collect(Collectors.toMap(Shop::getName, s -> EnumSet.copyOf(s.getProducts().stream() .map(Product::getCategory) .collect(Collectors.toSet())))); ,则您的实现将覆盖Map的值,而在name中可以使用合并功能实现,例如为Collectors.toMap

或者像FutureGene中所建议的那样更好:

(a,b) -> b

答案 1 :(得分:1)

使用Collectors.groupingByCollectors.flatMapping作为-

Map<String, EnumSet<Category>> categories =
        shops.stream()
            .collect(
                groupingBy(
                    Shop::getName,
                    flatMapping(
                        s -> s.getProducts().stream().map(Product::getCategory),
                        toCollection(() -> EnumSet.noneOf(Category.class)))));

Collectors.groupingBy组流基于Shop::getNameCollectors.flatMapping展开产品列表,并且map将产品映射到Product类别。 Collectors.flatMapping也是Collector<? super U, A, R> downstream,可用于收集EnumSet<Category>