Значение Java Stream Collectors.toMap является множеством

Я хочу использовать поток Java для запуска через список POJO, например, список List<A> ниже, и преобразовать его в карту Map<String, Set<String>>,

Например, класс А это:

class A {
    public String name;
    public String property;
}

Я написал код ниже, который собирает значения в карту Map<String, String>:

final List<A> as = new ArrayList<>();
// the list as is populated ...

// works if there are no duplicates for name
final Map<String, String> m = as.stream().collect(Collectors.toMap(x -> x.name, x -> x.property));

Тем не менее, потому что может быть несколько POJO с одним и тем же nameЯ хочу, чтобы значение карты было Set, Все property Струны для одного и того же ключа name должен идти в том же наборе.

Как это может быть сделано?

// how do i create a stream such that all properties of the same name get into a set under the key name
final Map<String, Set<String>> m = ???

4 ответа

Решение

groupingBy делает именно то, что вы хотите:

import static java.util.stream.Collectors.*;
...
as.stream().collect(groupingBy((x) -> x.name, mapping((x) -> x.property, toSet())));

Ответ @Nevay, безусловно, правильный путь, используя groupingBy, но это также достижимо toMap добавив функцию mergeFunction в качестве третьего параметра:

as.stream().collect(Collectors.toMap(x -> x.name, 
    x -> new HashSet<>(Arrays.asList(x.property)), 
    (x,y)->{x.addAll(y);return x;} ));

Этот код отображает массив на карту с ключом как x.name и значение как HashSet с одним значением как x.property, При наличии дублированного ключа / значения вызывается функция слияния третьего параметра для объединения двух HashSet.

PS. Если вы используете общую библиотеку Apache, вы также можете использовать их SetUtils::union как слияние

То же самое, но другое

Map<String, Set<String>> m = new HashMap<>();

as.forEach(a -> {
    m.computeIfAbsent(a.name, v -> new HashSet<>())
            .add(a.property);
    });

Кроме того, вы можете использовать параметр функции слияния функции Collectors.toMap Collectors.toMap(keyMapper,valueMapper,mergeFunction) следующим образом:

final Map<String, String> m = as.stream()
                                .collect(Collectors.toMap(
                                          x -> x.name, 
                                          x -> x.property,
                                          (property1, property2) -> property1+";"+property2);
Другие вопросы по тегам