Поток коллекцию карт в одну карту - PullRequest
0 голосов
/ 04 июня 2018

У меня есть коллекция карт.Внутренние карты могут иметь совпадающие ключи, поэтому я бы хотел превратить их в Map из Collection:

Collection<Map<String, Thing>> => Map<String, Collection<Thing>>

What I 'я пробовал:

Map<String, Collection<Thing>> newMap = oldCollection
    .stream()
    .map(Map::entrySet)
    .collect(Collectors.groupingBy(
             Entry::getKey,
             Collectors.mapping(Entry::getValue, Collectors.toList())));

Мне кажется, что это должно сработать, но я получаю ошибку компиляции:

Type mismatch: cannot convert from Map<Object,List<Object>> to Map<String,Collection<Thing>>

Кто-нибудь знает, что я делаю неправильно?

Ответы [ 4 ]

0 голосов
/ 04 июня 2018

Сначала проще создать карту:

Map<String, Collection<Thing>> map = new HashMap<>();

oldCollection.stream()
    .map(Map::entrySet)
    .flatMap(Set::stream)
    .forEach(e -> map.computeIfAbsent(e.getKey(), k -> new ArrayList<>()).add(e.getValue()));
0 голосов
/ 04 июня 2018

В качестве альтернативы вы можете сделать это следующим образом:

final Map<String, List<Thing>> thingsMap = oldCollection.stream()
        .map(Map::entrySet)
        .flatMap(Set::stream)
        .collect(Collectors.groupingBy(
            Map.Entry::getKey,
            Collectors.mapping(
                Map.Entry::getValue,  
                Collectors.toList()
            )
        ));

Вы можете получить набор записей каждой карты, там вы получите набор Наборов, а затем выровняете их, чтобы получить один большой Поток изих.Наконец вы обрабатываете этот большой поток.

0 голосов
/ 04 июня 2018

Для сравнения, это циклическое решение:

Map<String, Collection<Thing>> newMap = new HashMap<>();
for(Map<String, Thing> m: oldCollection)
    m.forEach((s,t) -> newMap.computeIfAbsent(s, x->new ArrayList<>()).add(t));

Вы можете выразить ту же логику, что и операция Stream:

Map<String, Collection<Thing>> newMap = oldCollection
    .stream()
    .collect(HashMap::new,
             (r,m)->m.forEach((s,t)->r.computeIfAbsent(s,x->new ArrayList<>()).add(t)),
             (r,m)->m.forEach((s,l)->r.computeIfAbsent(s,x->new ArrayList<>()).addAll(l)));

Это то же самое, что и другое решение, кромечто логика flatMap была интегрирована в коллектор.

0 голосов
/ 04 июня 2018

oldCollection.stream().map(Map::entrySet) создает Stream<Set<Map.Entry<String,Thing>>>, но вам нужно Stream<Map.Entry<String,Thing>>.

Поэтому вам необходимо использовать flatMap:

Map<String, List<Thing>>
    newMap = oldCollection.stream()
                          .flatMap(m->m.entrySet().stream())
                          .collect(Collectors.groupingBy(Map.Entry::getKey, 
                                                         Collectors.mapping(Map.Entry::getValue,
                                                                            Collectors.toList())));

Кроме того, поскольку вы отображаетесгруппированные значения равны List, тип вывода должен быть Map<String, List<Thing>>.

Вы можете изменить Collectors.toList() на Collectors.toCollection(ArrayList::new), если хотите сохранить текущий тип вывода.

...