Как заменить HashMap на LinkedhashMap с потоками? - PullRequest
0 голосов
/ 29 октября 2018

Не могли бы вы помочь мне разобрать мои Map?

У меня следующая структура, и я хочу собрать приложения под клиентами в LinkedHashMap в обратном порядке по значению.

[{
  "CUSTOMER_1": {
    "APP_1": "1"
  },
  "CUSTOMER_2": {
    "APP_1": "2",
    "APP_3": "7",
    "APP_2": "3"
  }
}]

У меня уже есть лямбда, которая собирает карту:

 final Map<String, Map<String, Long>> organizationApps = taskHandles.stream().map(this::mapPayload)
            .flatMap(e -> e.entrySet().stream())
            .collect(groupingBy(Map.Entry::getKey, of(HashMap::new,
                    (r, t) -> t.getValue().forEach((k, v) -> r.merge(k, v, Long::sum)),
                    (r1, r2) -> {
                        r2.forEach((v1, v2) -> r1.merge(v1, v2, Long::sum));
                        return r1;
                    }))
            );

Теперь мне нужно заменить organizationApps значения, представленные HashMap, на LinkedHashMap и поместить значения в LinkedHashMap в правильном порядке.

Как я могу сделать это в лямбде?

UPD:

Я могу добиться необходимого результата с помощью следующего кода:

    final Map<String, Map<String, Long>> organizationApps = taskHandles.stream().map(this::mapPayload)
            .flatMap(e -> e.entrySet().stream())
            .collect(groupingBy(Map.Entry::getKey, of(HashMap::new,
                    (r, t) -> t.getValue().forEach((k, v) -> r.merge(k, v, Long::sum)),
                    (r1, r2) -> {
                        r2.forEach((v1, v2) -> r1.merge(v1, v2, Long::sum));
                        return r1;
                    }))
            );

    organizationApps.forEach((key, value) -> {
        final Map<String, Long> sorted = value.entrySet()
                .stream()
                .sorted(reverseOrder(Map.Entry.comparingByValue()))
                .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2,
                        LinkedHashMap::new));
        organizationApps.put(key, sorted);
    });

Как я могу сделать это за одну лямбду?

1 Ответ

0 голосов
/ 30 октября 2018

Нельзя избежать сбора значений в карту, прежде чем вы сможете создать LinkedHashMap, упорядоченный по результирующим значениям, но вы можете указать шаг преобразования как финишер функция вашего пользовательского сборщика:

Map<String, Map<String, Long>> organizationApps = input.stream()
    .flatMap(e -> e.entrySet().stream())
    .collect(groupingBy(Map.Entry::getKey, Collector.of(HashMap::new,
        (r, t) -> t.getValue().forEach((k, v) -> r.merge(k, v, Long::sum)),
        (r1, r2) -> {
            r2.forEach((v1, v2) -> r1.merge(v1, v2, Long::sum));
            return r1;
        },
        (Map<String, Long> m) -> m.entrySet().stream()
            .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
            .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2,
                LinkedHashMap::new))
    )));

, что эквивалентно следующему (Java 9+) коду

Map<String, Map<String, Long>> organizationApps = input.stream()
    .flatMap(m -> m.entrySet().stream())
    .collect(groupingBy(Map.Entry::getKey, collectingAndThen(flatMapping(
            t -> t.getValue().entrySet().stream(),
            toMap(Map.Entry::getKey, Map.Entry::getValue, Long::sum)),
        (Map<String, Long> m) -> m.entrySet().stream()
            .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
            .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e2,
                LinkedHashMap::new))
    )));

В конце этот ответ является совместимой с Java 8 реализацией коллектора flatMapping, но ваш настраиваемый сборщик также выполняет свою работу.

...