Java 8 Stream Создание объекта из карты объектов - PullRequest
0 голосов
/ 01 сентября 2018

Я только начал изучать и реализовывать коллекции через потоковый API Java 8. У меня есть один класс:

public class Discount {
    int amount;
    String lastMarketingRegion;

    Discount (int amount, String lastMarketingRegion) {
        this.amount = amount;
        this.lastMarketingRegion= lastMarketingRegion;
    }

    public int getAmount() { return amount; }

    public String getLastMarketingRegion() { return lastMarketingRegion; }

    public String toString() {
        return String.format("{%s,\"%s\"}", amount, lastMarketingRegion);
    }
}

И мне дают следующее:

Map<String, Discount> prepaid = new HashMap<String, Discount>();
prepaid.put("HAPPY50", new Discount(100, "M1"));
prepaid.put("LUCKY10", new Discount(10, "M2"));
prepaid.put("FIRSTPAY", new Discount(20, "M3"));

Map<String, Discount> otherBills = new HashMap<String, Discount>();
otherBills.put("HAPPY50", new Discount(60, "M4"));
otherBills.put("LUCKY10", new Discount(7, "M5"));
otherBills.put("GOOD", new Discount(20, "M6"));

List<Map<String, Discount>> discList = new ArrayList<Map<String, Discount>>();
discList.add(prepaid);
discList.add(otherBills);

Итак, в основном у меня есть список Discount карт всех кодов скидок для различных типов платежей.

Требуется создать единую карту со всеми кодами скидок для всех типов платежей с помощью sum_of_amount и last_region:

Map<String, Discount> totalDiscounts = 
{LUCKY10={17, "M5"}, FIRSTPAY={20, "M3"}, HAPPY50={160, "M4"}, GOOD={20, "M6"}}

Я могу получить:

Map<String, Integer> totalDiscounts = 
    {LUCKY10=17, FIRSTPAY=20, HAPPY50=160, GOOD=20}

используя следующий код:

 Map<String, Integer> afterFormatting = discList.stream()
                           .flatMap(m -> m.entrySet().stream())
                           .collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.summingInt(map -> map.getValue().amount)));

но мне нужен Discount объект также с регионом.

Мне нужна коллекция объектов Discount, в которой сумма равна сумме одного и того же ключа, а регион - из других счетов.

Любая помощь будет высоко ценится. Спасибо.

Редактировать 1 - Для простоты, пожалуйста, учтите, что lastMarketingRegion имеет такое же значение для кода скидки. Я также пытался объяснить это с помощью диаграммы - enter image description here

Ответы [ 2 ]

0 голосов
/ 01 сентября 2018

Если у вас есть только две карты, то вместо того, чтобы использовать потоковое решение (мой другой ответ ), вы можете использовать Map.merge для этого.

Здесь мы делаем копию карты prepaid. Затем мы перебираем карту otherBills. За каждый ключ

  1. Если отображение не существует, оно добавляет его на карту (карту результатов)
  2. Если сопоставление уже существует, мы создаем новый объект Discount, сумма которого равна сумме сумм объекта Discount, уже присутствующего на карте (объект из prepaid), и текущего объекта Discount (объект из otherBill). Он берет область объекта Discount с карты otherBill.

Map<String, Discount> result = new HashMap<>(prepaid);
otherBills.forEach((k, v) -> result.merge(k, v, (discountFromPrepaid, discountFromOtherBill) ->
        new Discount(discountFromPrepaid.getAmount() + discountFromOtherBill.getAmount(),
                discountFromOtherBill.getLastMarketingRegion())));
0 голосов
/ 01 сентября 2018

из комментариев

Почему вы ожидаете "LUCKY10" - "M5", когда у вас есть записи "M2" и "M5" для LUCKY10?

, потому что другие счета имеют больший приоритет, чем предоплата

Вы можете использовать Collectors.toMap для этого. Последний аргумент - это mergeFunction, который объединяет две Скидки с одинаковым ключом String на карте.

Map<String, Discount> totalDiscounts = discList.stream()
            .flatMap(m -> m.entrySet().stream())
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                    (discount1, discount2) -> new Discount(discount1.getAmount() + discount2.getAmount(),
                            discount2.getLastMarketingRegion())));

Так как поток, сгенерированный из списка, упорядочен, discount2 Discount будет тем из карты otherBills, и поэтому я выбираю его область.

Если вы построили список, добавив otherBills с последующим prepaid, то это будет иметь другой вывод.

Опираясь на порядок столкновений, можно сделать это не лучшим решением . (Если вы предполагаете, что мы обрабатываем записи со второй карты после обработки первой, зачем объединять их в первую очередь?)

См. Мой другой ответ , который использует Map.merge

...