Следующий код работает и доступен для чтения, но мне кажется, что у меня есть промежуточные операции, которые чувствуют, что они не должны быть необходимы. Я написал эту упрощенную версию, поскольку фактический код является частью гораздо более крупного процесса.Java 8 Stream Collectors - Collector для создания карты с объектами в нескольких ведрах
У меня есть Collection
из Widget
, каждый из которых имеет имя и несколько типов (обозначенных константами перечня WidgetType
). Эти множественные типы получаются как Stream<WidgetType>
, хотя, если необходимо, я мог бы вернуть их как некоторые другие типы. (По разным причинам, это сильно желательно, что они будут возвращены в качестве Stream<WidgetType>
из-за того, как эти виджеты используются в дальнейшем в настоящем коде.)
Эти виджеты добавляются к EnumMap<WidgetType, List<Widget>>
который, позже, в переводе на a EnumMap<WidgetType, Widget[]>
.
Если каждый Widget
был только один WidgetType
, это было бы тривиально решить, но, так как любой виджет может иметь 1 или более типов, я расцепление все через себя с синтаксисом Collectors.groupingBy()
методы (и его перегрузок).
Вот пример кода, опять же, полностью функциональный и дает мне точный результат, который мне нужен.
class StackOverFlowExample {
private final Map<WidgetType, Widget[]> widgetMap = new EnumMap<>(WidgetType.class);
public static void main(String[] args) { new StackOverFlowExample(); }
StackOverFlowExample() {
Collection<Widget> widgetList = getWidgetsFromWhereverWidgetsComeFrom();
{
final Map<WidgetType, List<Widget>> intermediateMap = new EnumMap<>(WidgetType.class);
widgetList.forEach(w ->
w.getWidgetTypes().forEach(wt -> {
intermediateMap.putIfAbsent(wt, new ArrayList<>());
intermediateMap.get(wt).add(w);
})
);
intermediateMap.entrySet().forEach(e -> widgetMap.put(e.getKey(), e.getValue().toArray(new Widget[0])));
}
Arrays.stream(WidgetType.values()).forEach(wt -> System.out.println(wt + ": " + Arrays.toString(widgetMap.get(wt))));
}
private Collection<Widget> getWidgetsFromWhereverWidgetsComeFrom() {
return Arrays.asList(
new Widget("1st", WidgetType.TYPE_A, WidgetType.TYPE_B),
new Widget("2nd", WidgetType.TYPE_A, WidgetType.TYPE_C),
new Widget("3rd", WidgetType.TYPE_A, WidgetType.TYPE_D),
new Widget("4th", WidgetType.TYPE_C, WidgetType.TYPE_D)
);
}
}
Это выводит:
TYPE_A: [1st, 2nd, 3rd]
TYPE_B: [1st]
TYPE_C: [2nd, 4th]
TYPE_D: [3rd, 4th]
Для полноты, вот Widget
класс и WidgetType
перечисление:
class Widget {
private final String name;
private final WidgetType[] widgetTypes;
Widget(String n, WidgetType ... wt) { name = n; widgetTypes = wt; }
public String getName() { return name; }
public Stream<WidgetType> getWidgetTypes() { return Arrays.stream(widgetTypes).distinct(); }
@Override public String toString() { return name; }
}
enum WidgetType { TYPE_A, TYPE_B, TYPE_C, TYPE_D }
Любые идеи о лучшем способе выполнения этой логики приветствуются. Благодаря!
Это все еще нуждается в шаге от '' Список к 'Widget []'. Может использовать 'collectAndThen (toList(), l -> l.toArray (новый Widget [0])). –
Спасибо, @JornVernee. Ред. –
'Collectors.mapping()' это часть, которую мне не хватало. Решение 'collectAndThen()' тоже является бонусом. (Я очень смирился с требованием этого дополнительного шага.) Пригвоздил его, Люк. +1 весь день. Бесконечно благодарен! :) – Darkly