[英]Java stream/collect: map one item with multiple fields to multiple keys
[英]Java stream collect to map with multiple keys
我以為我已經很擅長 Java 8 流了,但后來……
我有一個Foo
接口:
public interface Foo {
String getKey();
Stream<Bar> bars();
}
我知道我可以使用每個鍵將Stream<Foo>
收集到Map<String, Foo>
中:
Map<String, Foo> foosByKey = fooStream.collect(
Collectors.toMap(Foo::getKey, Function.identity()));
但是如果我想將它們收集到Map<Bar, Foo>
怎么辦? 換句話說,對於 Steam 中的每個Foo
,我想將該Foo
放入映射到每個由Foo.bars()
返回的Bar
實例的Foo.bars()
。 我從哪里開始?
正如此處所建議的,您需要從每個Foo
提取Bar
值並創建它們對。 獲得對后,您可以將它們收集到Map
。 例如,
Map<Bar, Foo> map = fooStream.flatMap(foo -> foo.bars().map(bar -> new SimpleEntry<>(bar, foo)))
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
我們在這里使用SimpleEntry
是因為它可用(Java 沒有更簡單的Pair
類型)。 你可以自己寫一個更具體的。
您可以為此定義一個新的收集器。 一個簡單的實現(總是創建 ArrayList 的 HashMap;沒有下游支持)可以是:
public static <T, K>
Collector<T, ?, Map<K, List<T>>> multiGroupingBy(
Function<? super T, Collection<? extends K>> multiClassifier) {
return Collector.of(
HashMap::new,
(map, entry) -> {
multiClassifier.apply(entry)
.forEach(
key -> map
.computeIfAbsent(key,
__ -> new ArrayList<>())
.add(entry));
},
(map1, map2) -> {
map2.forEach(
(key, list) -> map1
.computeIfAbsent(key,
__ -> new ArrayList<>())
.addAll(list));
return map1;
});
}
然后你可以調用:
fooStream.collect(multiGroupingBy(Foo::bars));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.