Java 8 Collectors.groupingBy с отображенным значением, чтобы установить результат сбора в тот же набор - PullRequest
0 голосов
/ 27 ноября 2018

Объекты, используемые в примере, взяты из пакета org.jsoup.nodes

import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

Мне нужны групповые атрибуты по ключу с результирующим значением Set.

Optional<Element> buttonOpt = ...;
Map<String, Set<String>> stringStringMap =
    buttonOpt.map(button -> button.attributes().asList().stream()
            .collect(groupingBy(Attribute::getKey, 
                  mapping(attribute -> attribute.getValue(), toSet()))))
            .orElse(new HashMap<>());

Кажется, все собрано правильно,но значение все время представляет собой одну строку (из-за реализации библиотеки), которая содержит различные значения, разделенные пробелом.Пытаюсь улучшить решение:

Map<String, Set<HashSet<String>>> stringSetMap = buttonOpt.map(
        button -> button.attributes()
            .asList()
            .stream()
            .collect(groupingBy(Attribute::getKey, 
                        mapping(attribute -> 
                          new HashSet<String>(Arrays.asList(attribute.getValue()
                                                                .split(" "))),
                   toSet()))))
  .orElse(new HashMap<>());

В результате у меня другая структура Map<String, Set<HashSet<String>>>, но мне нужно Map<String, Set<String>>

Я проверил некоторые коллекторы, но не справился с проблемой.

Вопрос:

Как объединить все наборы, связанные с одним и тем же ключом атрибута?

Ответы [ 3 ]

0 голосов
/ 27 ноября 2018

Вот способ Java9 сделать это,

Map<String, Set<String>> stringSetMap = buttonOpt
    .map(button -> button.attributes().asList().stream()
        .collect(Collectors.groupingBy(Attribute::getKey, Collectors.flatMapping(
            attribute -> Arrays.stream(attribute.getValue().split(" ")), Collectors.toSet()))))
    .orElse(Collections.emptyMap());
0 голосов
/ 27 ноября 2018

Это становится менее сложным, если вы используете для него более подходящую структуру данных, а именно: multimap .

Мультикарты присутствуют, например, в Guava , где вы можетесделать это следующим образом:

SetMultimap<String, String> stringMultimap = buttonOpt
        .map(button -> button.attributes().asList().stream()
                .collect(ImmutableSetMultimap.flatteningToImmutableSetMultimap(
                        Attribute::getKey,
                        attribute -> Arrays.stream(attribute.getValue().split(" "))
                ))
        ).orElse(ImmutableSetMultimap.of());

Я сделал его неизменным (ImmutableSetMultimap), но изменяемая версия также может быть получена с использованием Multimaps.flatteningToMultimap.

0 голосов
/ 27 ноября 2018

Вы можете разделить свои атрибуты с помощью flatMap и создать новые записи для группы:

Optional<Element> buttonOpt = ...
Map<String, Set<String>> stringStringMap =
        buttonOpt.map(button -> 
            button.attributes()
                  .asList()
                  .stream()
                  .flatMap(at -> Arrays.stream(at.getValue().split(" "))
                                       .map(v -> new SimpleEntry<>(at.getKey(),v)))
                  .collect(groupingBy(Map.Entry::getKey, 
                                      mapping(Map.Entry::getValue, toSet()))))
                .orElse(new HashMap<>());
...