Summing BigDecimals in streams API Collectors

Ares02 :

My current attempt is based on double type class members:

public Client whoPaidTheMost() {

/*METHOD EXPLOITING STREAM API*/

return shopping.entrySet()
        .stream()
        .collect(Collectors.groupingBy(Map.Entry::getKey,
                Collectors.flatMapping(e -> e.getValue().entrySet().stream(),
                        Collectors.summingDouble(e->e.getKey().getPrize() * e.getValue())))) /*should be refactored*/
        .entrySet().stream()
        .max(Comparator.comparingDouble(Map.Entry::getValue))/*should be refactored*/
        .get()
        .getKey();
}

shopping is basically a map: Map<Client, Map<Product,Integer>>,

  • The outer Key represents the Client
  • The inner Key represents the Product
  • the inner maps value (Integer) reprents the number of specified product which belong to a specific client

Product class members are name, category, price (previously of double type) - want to refactor the provided code into one using price as a type of BigDecimal

How could I make this code work also for BigDecimals - ?

Basically I' ve refactored that arleady:

  Client client = shopping.entrySet()
            .stream()
            .collect(Collectors.groupingBy(Map.Entry::getKey,
                    Collectors.flatMapping(e -> e.getValue().entrySet().stream(),
                            Collectors.mapping(e -> BigDecimal.valueOf(new Long(e.getValue())).multiply(e.getKey().getPrize()),
                                    Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)))))
            .entrySet().stream()
            .max((e1, e2) -> (e1.getValue().compareTo(e2.getValue())))
            .get()
            .getKey();

Still wondering if it's possible to refactor this without using: Collectors.mapping(e -> BigDecimal.valueOf(new Long(e.getValue())).multiply(e.getKey().getPrize()) before Collectors.reducing ?

Ravindra Ranwala :

You can refactor it like this,

shopping.entrySet().stream()
    .collect(
        Collectors.groupingBy(Map.Entry::getKey,
            Collectors.flatMapping(
                e -> e.getValue().entrySet().stream()
                    .map(innerEntry -> innerEntry.getKey().getPrice()
                    .multiply(BigDecimal.valueOf(innerEntry.getValue()))),
            Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))))
    .entrySet().stream()
    .max(Map.Entry.comparingByValue()).get().getKey();

You don't need any additional mapping Collector here. Merely use the map operator to convert your Map.Entry into a BigDecimal based on your computation, and pass that Stream<BigDecimal> down. The final reduction operator does the trick here. Zero acts as a good identity element for this sum.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=81463&siteId=1