Search code examples
javajava-stream

Java stream transform list of objects to a grouped map by objects list type attribute


I'm learning java stream grouping and don't really know the keyword to search for my problem. I have a Product class:

class Product {
   private String name;
   private List<String> types;
}

I have a list of products:

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

List<String> type1 = new ArrayList<>();
type1.add("typeA");
type1.add("typeB");
products.add(new Product("product1", type1));

List<String> type2 = new ArrayList<>();
type2.add("typeB");
type2.add("typeC");
products.add(new Product("product2", type2));

List<String> type3 = new ArrayList<>();
type3.add("typeA");
type3.add("typeC");
products.add(new Product("product3", type3));

By using stream, how can I get a map grouping by type of products:

{
   "typeA": [product1, product3],
   "typeB": [product1, product2],
   "typeC": [product2, product3]
}

Thank you


Solution

  • You can use the Collectors.groupingBy() method to group the products by their types.

    Map<String, List<Product>> productsByType = products.stream()
    .flatMap(p -> p.getTypes().stream().map(t -> new AbstractMap.SimpleEntry<>(t, p)))
    .collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
    

    The code is creating a map that groups products by their types. It does this by first transforming the list of products into a stream of key-value pairs, where each key is a product type and each value is the corresponding product. It then collects these key-value pairs into a map using the groupingBy() method, with the product type as the key and a list of products that have that type as the value.

    To create the key-value pairs in the stream, the code uses the AbstractMap.SimpleEntry class, which is a simple way to represent a key-value pair. Finally, the code assumes that there is a method in the Product class that returns the list of product types.

    You can print them and get your expected result by forEach method

    productsByType.forEach((k,v)-> System.out.println(k + " " + v));
    

    also don't forget to override toString method on the product class

    @Override
    public String toString() {
        return name;
    }