Как сгруппировать значения карты в списки по ключу с java потоками? - PullRequest
0 голосов
/ 07 февраля 2020

Скажем, у меня есть сопоставления из строк в сопоставление из строк в int, например

Map<String, Map<String, Integer>> myMap1 = new HashMap<>();
myMap1.put("A", Map.of("X", 1))
myMap1.put("B", Map.of("Y", 1))

Map<String, Map<String, Integer>> myMap2 = new HashMap<>();
myMap2.put("B", Map.of("Y", 3))

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

{"X" : 1, "Y", 2}

. Мы можем полностью отбросить ключ внешней карты.

Какой самый хороший способ сделать это с java. Я подумал, что может быть какой-то хороший способ сделать это с помощью метода Collectors.groupBy, но я совершенно неопытен в этом.

1 Ответ

2 голосов
/ 07 февраля 2020

Я собираюсь предположить, что может быть более двух карт, поэтому давайте сделаем из них список:

    Collection<Map<String, Map<String, Integer>>> myMaps =
        List.of(myMap1, myMap2);

Затем мы можем использовать flatMap на values() каждой карты, что дает нам поток Map<String, Integer> карт.

Мы можем получить entrySet() каждого из них, а затем применить flatMap к потокам этих наборов входов, чтобы получить один поток из Map.Entry<String, Integer> объектов. , который мы затем можем сгруппировать.

Существует метод groupingBy, который использует второй Collector для настройки значений групп, собирая все видимые сгруппированные значения. Мы можем использовать это, чтобы получить наши средние значения, используя усредняющий коллектор .

Map<String, Double> averages =
    myMaps.stream().flatMap(map -> map.values().stream())       // stream of Map<String, Integer>
        .flatMap(innerMap -> innerMap.entrySet().stream())      // stream of Map.Entry<String, Integer>
        .collect(Collectors.groupingBy(Map.Entry::getKey,       // group by String key
            Collectors.averagingInt(Map.Entry::getValue)));     // value for each key = average of its Integers
...