Java: объединение значений карты, содержащей наборы

#java #dictionary #set

Вопрос:

Рассмотрим следующие псевдо Map<String, Set<String>> :

 {
    "1": ["A", "B"],
    "2": ["A", "C"],
    "3": ["D", "B", "A", "C"],
    "4": ["C", "A", "B"],
    "5": ["A", "B"],
}
 

Каков наилучший способ объединить наборы значений в один набор (должен быть приведен пример выше ["A", "B", "C", "D"] ). Порядок результирующего набора не имеет значения.

Я знаю, что могу сделать что-то подобное:

 Collection<Set<String>> values = myMap.values();
Set<String> unique = new HashSet<>();

for (Set<String> v : values) {
    for (String s : v) {
        if (!unique.contains(s)) unique.add(s);
    }
}
 

Но это кажется немного уродливым, и мне интересно, есть ли лучший (и более «встроенный») способ сделать это?

Комментарии:

1. Прежде всего, вам не нужно проверять, содержит ли набор уже значение, которое вы собираетесь добавить. Набору все равно, и он просто проигнорирует, если значение уже присутствует.

Ответ №1:

Используйте этот Set.addAll(Collection) метод; см. javadoc.

 Collection<Set<String>> values = myMap.values();
Set<String> unique = new HashSet<>();

for (Set<String> v : values) {
    unique.addAll(v);
}
 

Логика должна быть самоочевидной.

Мета-урок: рекомендуется ознакомиться с возможностями API, которые вы используете, просматривая javadocs.

Ответ №2:

На самом деле вам не нужно проверять, содержит ли a Set уже значение, которое вы собираетесь добавить. Вот почему вы в первую очередь хотели бы использовать набор.

Если этот набор уже содержит элемент, вызов оставляет набор неизменным и возвращает значение false.

из Set#add(E) Javadoc

Имея это в виду, единственное, что вам нужно будет сделать, это на самом деле просмотреть свои Set s и объединить значения в один набор, не беспокоясь о дубликатах.

Одно решение via addAll() уже было предоставлено, поэтому я подумал, что предложу альтернативное решение с использованием потоков Java 8:

 Set<String> unique = myMap.values() // gets the values (all sets) from the map
    .stream()                       // stream of values
    .flatMap(Set::stream)           // flattens all sets (in values) in to single stream
    .collect(Collectors.toSet());   // collects the values into single set