Стандартный подход использует flatMap
перед сбором, используя groupingBy
, но, поскольку вам нужен исходный Square
для каждого элемента, вам необходимо отобразить объект, содержащий и экземпляр Square
, и код zuloString
.
Поскольку в Java нет стандартной пары или типа кортежа (пока), обходной путь - использовать экземпляр Map.Entry
, например
private Map<String, Set<Square>> populateZuloSquare0(List<Square> squares) {
if (squares == null || squares.isEmpty()) {
return emptyMap();
}
return squares.stream()
.filter(square -> logMismatch(square, !square.getZuloCodes().isEmpty()))
.flatMap(square -> square.getZuloCodes().stream()
.map(code -> new AbstractMap.SimpleEntry<>(code, square)))
.collect(Collectors.collectingAndThen(
Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toSet())),
Collections::unmodifiableMap));
}
private static boolean logMismatch(Square square, boolean match) {
if(!match) LOG("Ignored {}", square.id);
return match;
}
Anальтернативой является использование настраиваемого сборщика, который будет перебирать ключи:
private Map<String, Set<Square>> populateZuloSquare(List<Square> squares) {
if (squares == null || squares.isEmpty()) {
return emptyMap();
}
return squares.stream()
.filter(square -> logMismatch(square, !square.getZuloCodes().isEmpty()))
.collect(Collector.of(
HashMap<String, Set<Square>>::new,
(m,square) -> square.getZuloCodes()
.forEach(code -> m.computeIfAbsent(code, x -> new HashSet<>()).add(square)),
(m1,m2) -> {
if(m1.isEmpty()) return m2;
m2.forEach((key,set) ->
m1.merge(key, set, (s1,s2) -> { s1.addAll(s2); return s1; }));
return m1;
},
Collections::unmodifiableMap)
);
}
Обратите внимание, что этот настраиваемый сборщик можно рассматривать как вариант параллельного кода следующего цикла:
private Map<String, Set<Square>> populateZuloSquare(List<Square> squares) {
if (squares == null || squares.isEmpty()) {
return emptyMap();
}
Map<String, Set<Square>> res = new HashMap<>();
squares.forEach(square -> {
if(square.getZuloCodes().isEmpty()) LOG("Ignored {}", square.id);
else square.getZuloCodes().forEach(
code -> res.computeIfAbsent(code, x -> new HashSet<>()).add(square));
});
return Collections.unmodifiableMap(res);
}
что может показаться не таким уж плохим сейчас, когда вам не нужен код для параллельной работы…