javasortingjava-streamgroupingby

groupingBy in Streams with CollectingAndThen method -> how to get rid of Optional then use Max on the map :)


Seems like i do not quite understand the concepts of groupingBy & collectors & sorting.

Task: to sum the number of order's quantity grouped by Category using Streams. Then get category with Max quantity and print it out on the picture as single map row with top value

3 classes (2 Records: Product & Order + Main). In Main there is an List.of new orders

Class Product:

public record Product(String name, BigDecimal price, String category)

Class Order:

public record Order(Product product, int quantity, BigDecimal discount)

public BigDecimal priceWithDiscount(){
    return product.price().multiply(BigDecimal.ONE.subtract(discount));
}

Class Main

       List<Order> orders = List.of(
            new Order(new Product("chleb", new BigDecimal(5), "A"),10, new BigDecimal("0.1")),
            new Order(new Product("maslo", new BigDecimal(6), "A"),5, new BigDecimal("0.2")),
            new Order(new Product("szynka", new BigDecimal(25), "B"),10, new BigDecimal("0")),
            new Order(new Product("kielbasa", new BigDecimal(16),"C"),5, new BigDecimal("0")),
            new Order(new Product("woda", new BigDecimal(3),"B"),15, new BigDecimal("0.1")),
            new Order(new Product("ocet", new BigDecimal(3),"A"),8, new BigDecimal("0.3")),
            new Order(new Product("margaryna", new BigDecimal(4),"B"),12, new BigDecimal("0.5")),
            new Order(new Product("maslo", new BigDecimal(8),"C"),5, new BigDecimal("0.2"))
            )

Below my implementation of grouping:

        Map<String, Optional<Integer>> summedQuantitiesPerCategory = orders //no 1.
            .stream()
            .collect(Collectors.groupingBy(p -> p.product().category(),
                    Collectors.collectingAndThen(
                            Collectors.mapping(p -> p.quantity(), Collectors.toList()),
                            quantity -> quantity.stream().reduce((x, y) -> x + y) 
                    )));


        summedQuantitiesPerCategory
            .entrySet()
            .stream()
            .sorted(Comparator.comparing(p -> p.getValue())) // no2.
            .limit(1);

Questions:

  1. How to get rid of this Optional and see only Integer as a value in the map. Then it would be easy to sort i guess
  2. How to sort map via Value using method Sorted or something more simple like e.g. max?

Solution

  • You are using the one argument version of reduce which accepts a BinaryOperator. You can pass an identity value along with the BinaryOperator.

    quantity -> quantity.stream().reduce(0, (x, y) -> x + y)
    

    or

    quantity -> quantity.stream().reduce(0, Integer::sum)
    

    Since you just want to sum the quantity, you can use Collectors.summingInt

    ...
    .collect(Collectors.groupingBy(p -> p.product().category(),
                    Collectors.summingInt(p -> p.quantity())));