首页 > 解决方案 > 通过合并具有相同 Id 的集合中的两个对象来创建一个新对象,并将生成的对象添加到不同的集合中

问题描述

我有一组对象, ProductDetails 具有以下字段,

public class ProductDetails {

    String productId;

    Set<CityQty> qtyByCities;

}

@EqualsAndHashCode(of = {"name"})
public class CityQty {
    String name;
    int qty;
}

我想将其转换为一组 CityQty,其中每个城市都有所有产品的总数量。

示例输入:

[{"productId":"Item01","qtyByCities":[{"name":"New York", "qty":24},{"name":"Washington", "qty":68}]},
{"productId":"Item02","qtyByCities":[{"name":"New York", "qty":20}]}]

示例输出:

[{"name":"New York", "qty":44},{"name":"Washington", "qty":68}]

我编写了以下代码来实现这一点:

Set<CityQty> cities = new HashSet<>();
setOfItems.stream().flatMap(product -> product.getQtyByCities().stream())
    .forEach(cityQty -> {
        String cityName = cityQty.getName();
        CityQty city = cities.stream()
                             .filter(cityQty -> cityQty.getName().equals(cityName))
                             .findFirst()
                             .orElse(new CityQty(cityName, 0));
        city.setQty(city.getQty() + cityQty.getQty());
        cities.add(city);
});

上面的解决方案工作正常,但我正在寻找一个更优雅的解决方案,可能使用我在这里缺少的任何 Java 8 功能,这不需要我为lambdacities内的每次迭代遍历集合。forEach

这个问题能不能更有效、更简洁地解决?

标签: javadictionaryjava-8setjava-stream

解决方案


你可以利用Collectors类。有关更多详细信息,请参阅javadoc。这是一个使用示例groupingBy

Map<String, Integer> m = setOfItems.stream()
    .flatMap(product -> product.getQtyByCities().stream())
    .collect(groupingBy(CityQty::getName, summingInt(CityQty::getQty)));

你最终会得到一张地图:名字 - 总和。如果你想得到一套,你可以使用map

m.entrySet().stream().map(e -> new CityQty(e.getKey(), e.getValue())).collect(toSet());

推荐阅读