Создайте новый объект путем объединения двух объектов в наборе с одинаковым идентификатором и добавьте полученный объект в другой набор - PullRequest
1 голос
/ 25 января 2020

У меня есть набор объектов, 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, которую я здесь упускаю, которая не требует от меня повторения набора cities для каждой итерации внутри forEach лямбда.

Можно ли решить эту проблему более эффективно и лаконично?

1 Ответ

3 голосов
/ 25 января 2020

Вы можете использовать Collectors класс. Смотрите javado c для более подробной информации. Вот пример использования groupingBy:

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

В итоге вы получите карту: name - sum. Если вы хотите получить набор, вы можете использовать map:

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