Grouping and summing with BigDecimal in parallel in java 8

I have a list of products with the amount of one of the attributes. And the list may contain the common name of the product, and other attributes are different. Therefore, I want to group the list by product and the sum of the sum of products that have a common name in java 8 using grouping and summation.

Example:
[  
   {  
      "name":"Product A",
      "amount":"40.00",
      "description":"Info1",
      "number":"65"
   },
   {  
      "name":"Product A",
      "amount":"50.00",
      "description":"Info2",
      "number":"67"
   },
   {  
      "name":"Product A",
      "amount":"100.00",
      "description":"Info3",
      "number":"87"
   },
   {  
      "name":"Product B",
      "amount":"45.00",
      "description":"Info4",
      "number":"86"
   },
   {  
      "name":"Product D",
      "amount":"459.00",
      "description":"Info5",
      "number":"7"
   },
   {  
      "name":"Product B",
      "amount":"50.00",
      "description":"Info6",
      "number":"8"
   }
]

The output should be similar to this:

{  
   "Product A = 190.00":[  
      {  
         "name":"Product A",
         "amount":"40.00",
         "description":"Info1",
         "number":"65"
      },
      {  
         "name":"Product A",
         "amount":"50.00",
         "description":"Info2",
         "number":"67"
      },
      {  
         "name":"Product A",
         "amount":"100.00",
         "description":"Info3",
         "number":"87"
      }
   ],
   "Product B=95.00":[  
      {  
         "name":"Product B",
         "amount":"45.00",
         "description":"Info4",
         "number":"86"
      },
      {  
         "name":"Product B",
         "amount":"50.00",
         "description":"Info6",
         "number":"8"
      }
   ],
   "Product D = 459.00":[  
      {  
         "name":"Product D",
         "amount":"459.00",
         "description":"Info5",
         "number":"7"
      }
   ]

I created a bean class ProductBeanthat has all the fields (name, quantity, description and number), as well as recipients and setters for the same. And productBeans has a list of all products.

Map<String, List<ProductBean>> groupByProduct = 
               productBeans.stream()
                     .collect(Collectors.groupingBy(item -> item.getName()))

Map<String, BigDecimal> result = 
      productBeans.stream()
             .collect(Collectors.groupingBy(ProductBean::getName, 
                                Collectors.mapping(ProductBean::getAmount, 
                     Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));

groupByProduct has a list of products grouped by name. the result gives a product map as a key and the total amount of this product as a value.

. , , . .

, , , .

+4
3

, - Map<String, BigDecimal, List<ProductBean>>, String name, BigDecimal - List<ProductBean>, .

, , , , .

- - :

class ResultSet {

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }

    public List<ProductBean> getProductBeans() {
        return productBeans;
    }

    public void setProductBeans(List<ProductBean> productBeans) {
        this.productBeans = productBeans;
    }

    private String name;
    private BigDecimal amount;
    private List<ProductBean> productBeans;

    @Override
    public String toString() {
        return "ResultSet{" +
                "name='" + name + '\'' +
                ", amount=" + amount +
                ", productBeans=" + productBeans +
                '}';
    }
}

ProductBean's, , , , , .

:

List<ResultSet> result = productList.stream()
                .collect(Collectors.groupingBy(ProductBean::getName))
                .entrySet()
                .stream()
                .map(e -> {
                    ResultSet resultSet = new ResultSet();
                    BigDecimal sum = e.getValue().stream()
                            .map(ProductBean::getAmount)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    resultSet.setName(e.getKey());
                    resultSet.setAmount(sum);
                    resultSet.setProductBeans(e.getValue());
                    return resultSet;
                }).collect(Collectors.toList());

ProductBean, ResultSet, , ProductBean's .

, :

private static ResultSet mapToResultSet(Map.Entry<String, List<ProductBean>> e) {
        ResultSet resultSet = new ResultSet();
        BigDecimal sum = e.getValue().stream()
                .map(ProductBean::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        resultSet.setName(e.getKey());
        resultSet.setAmount(sum);
        resultSet.setProductBeans(e.getValue());
        return resultSet;
}

, :

List<ResultSet> result = productList.stream()
                .collect(Collectors.groupingBy(ProductBean::getName))
                .entrySet()
                .stream()
                .map(Main::mapToResultSet) // Main representing the class containing the mapToResultSet method
                .collect(Collectors.toList());
+3

, .

Collectors.groupingBy , , . :

    Map<String, BigDecimal> result = productBeans
            .stream()
            .collect(
                Collectors.groupingBy(ProductBean::getName,
                Collectors.mapping(ProductBean::getAmount, 
                    Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));
0

In addition to my previous answer, which recommends creating a wrapper class. if for some reason you do not want to create a custom class solely for wrapping the results, then another solution looks like this:

List<AbstractMap.SimpleEntry<Map.Entry<String, List<ProductBean>>, BigDecimal>> 
         resultSet =
                productBeans.stream()
                            .collect(Collectors.groupingBy(ProductBean::getName))
                            .entrySet()
                            .stream()
                            .map(Main::mapToSimpleEntry)
                            .collect(Collectors.toList());

where Mainis the class containing mapToSimpleEntry, and mapToSimpleEntryis defined as:

private static AbstractMap.SimpleEntry<Map.Entry<String, List<ProductBean>>, BigDecimal> mapToSimpleEntry(Map.Entry<String, List<ProductBean>> e) {
        BigDecimal sum =
                e.getValue().stream()
                        .map(ProductBean::getAmount)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
        return new AbstractMap.SimpleEntry<>(e, sum);
}

This solution has the advantage that:

  • no need to create a custom class
  • less code
0
source

Source: https://habr.com/ru/post/1696178/


All Articles