我列出了数量之一的产品。并且列表可以包含通用产品名称,其他属性也不同。所以我想通过分组和求和来按Java 8中共享通用名称的产品和产品数量之和对列表进行分组。

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"
   }
]

输出应类似于以下内容:
{
   "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"
      }
   ]

我创建了一个Bean类ProductBean,它具有所有字段(名称,数量,描述和数字)以及相同的getter和setter。
productBeans列出了所有产品。
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具有按名称分组的产品列表。
结果给出产品图作为关键,并给出该产品的总价值。

但是在这里,我试图将产品和总量映射到产品列表。我试图结合以上代码来获得预期的输出,但无法实现。通过遍历地图可以达到相同的目的。

但是,将上述代码合并以得到产品名称和数量作为键,列表作为值的映射的任何帮助都是有帮助的。

最佳答案

似乎您想要Map<String, BigDecimal, List<ProductBean>>之类的东西,其中String表示nameBigDecimal是所有产品金额的总和,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());

08-17 22:38