我列出了数量之一的产品。并且列表可以包含通用产品名称,其他属性也不同。所以我想通过分组和求和来按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表示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());