У меня есть список элементов:
List<OuterElement> outerElements;
Объект OuterElement имеет 2 свойства:
String key;
List<InnerElement> innerElements;
Объект InnerElement имеет 1 свойство:
String value;
Мне нужно создать карту, где для каждого внутреннего элемента будет создана запись, где ключ будет ключом внешнего элемента, а значение будет значением внутреннего элемента;
Map<String, String> // actually Map<OuterElement.key, InnerElement.value>
Как это сделать с помощью Stream API?
Я пробовал что-то вроде этого, но это не работает:
Map<String, String> result = outerElements.stream()
.forEach(outerElement -> outerElement.getInnerElements().stream().collect(Collectors.toMap(OuterElement::getKey, InnerElement::getValue));
Что должно произойти, если два внешних элемента в списке имеют один и тот же ключ? А поскольку у каждого внешнего элемента есть список внутренних элементов, каждый из которых имеет значение, не очень понятно, что вы ищете. Например, представьте, что у вас есть [OuterElement(key=x, innerElements=[InnerElement(value=y), InnerElement(value=z)]), OuterElement(key=a, innerElements=[InnerElement(value=b), InnerElement(value=c)])]. Каким должен быть результат?
Map<OuterElement.key, InnerElement.value> — это связь «один к одному», в то время как у вас есть связь «один ко многим» (это либо Map<OuterElement.key, Set<InnerElement.value>>, либо Map<OuterElement.key, List<InnerElement.value>>)
Дайте нам пример возможного ввода и ожидаемого результата (это, вероятно, позволит ты понять, почему ваша попытка «не работает», и позволит вам принять решение, что делать вместо этого).




В дополнение к ответу Руслан для java 8 вы можете использовать этот:
Map<String, List<String>> collect = elements.stream()
.collect(Collectors.groupingBy(OuterElement::getKey,
Collectors.collectingAndThen(Collectors.toList(), outers -> outers.stream()
.flatMap(o -> o.getInnerElements().stream())
.map(InnerElement::getValue)
.collect(Collectors.toList()))));
если бы вы могли использовать что-то вроде MultiValueMap:
MultiValueMap<String, String> map = elements.stream()
.collect(Collectors.groupingBy(OuterElement::getKey,
LinkedMultiValueMap::new,
Collectors.collectingAndThen(Collectors.toList(), outers -> outers.stream()
.flatMap(o -> o.getInnerElements().stream())
.map(InnerElement::getValue)
.collect(Collectors.toList()))));
Следует сказать, что MultiValueMap взято из фреймворка Spring, но в любом случае +1 за решение
Ключи в карте должны быть уникальными, поэтому если у вас есть
outer:key, inner[val1,val2], то ваша карта не может бытьkey:val1, key:val2. Это может бытьkey:[val1,val2], но для этого потребуется изменить его сMap<String,String>наMap<String,List<String>>.