:あなたは後にしているものを達成することができます
private static Collector<Collection<SomeClassB>, ?, ImmutableList<SomeClassB>>
flatMapToImmutableList() {
return Collectors.collectingAndThen(Collectors.toList(),
listOfCollectionsOfB ->
listOfCollectionsOfB.stream()
.flatMap(Collection::stream)
.collect(GuavaCollectors.toImmutableList()));
}
)、あなたはあなたが望むものを達成するために独自のコレクターを書くことができます:
public static <T, D, R> Collector<T, ?, R> flatMapping(
Function<? super T, ? extends Stream<? extends D>> streamMapper,
Collector<? super D, ?, R> downstream) {
class Acc {
Stream.Builder<Stream<? extends D>> builder = Stream.builder();
void add(T t) {
builder.accept(streamMapper.apply(t));
}
Acc combine(Acc another) {
another.builder.build().forEach(builder);
return this;
}
R finish() {
return builder.build()
.flatMap(Function.identity()) // Here!
.collect(downstream);
}
}
return Collector.of(Acc::new, Acc::add, Acc::combine, Acc::finish);
}
このヘルパーメソッドは、 Collector.of
およびローカルクラスAcc
を使用して、指定されたstreamMapper
関数によって返されたストリームを累積します。この関数は、元のストリームの要素を引数として取ります。これらのストリームは、コレクタのフィニッシャ機能が適用されたときに構築されるStream.Builder
に蓄積されます。
このストリームのストリームが作成された直後は、ストリームを連結したいだけなので、ストリームはアイデンティティ関数でフラット・マップされます。 (私はストリームのストリームの代わりにストリームのリストを使用することができたかもしれないが、私はStream.Builder
が非常に効率的であり、十分に活用されていないと思う)。
Acc
は、Acc
のストリームストリームをこのAcc
のストリームビルダーにマージするコンバイナメソッドも実装しています。この機能は、元のストリームがパラレルの場合にのみ使用されます。ここで
はあなたの例で、このメソッドを使用する方法は次のとおりです。
Map<String, Map<String, ImmutableList<SomeClassB>>> map = someListOfClassA.stream()
.filter(...)
.collect(
Collectors.groupingBy(SomeClassA::getSomeCriteriaA,
Collectors.groupingBy(SomeClassA::getSomeCriteriaB,
flatMapping(
a -> getSomeClassBsFromSomeClassA(a).stream(),
ImmutableList.toImmutableList()))));
EDIT: @Holgerが蓄積したときに、ストリームビルダにデータをバッファリングする必要はありません、以下のコメントで示したよう。代わりに、フラット・マッピング・コレクタは、アキュムレータ機能で平坦化の権利を実行することによって実装できます。Here is @Holger's own implementation of such collector、私は彼の同意を得て、そのままここにコピーしていた:
public static <T, U, A, R> Collector<T, ?, R> flatMapping(
Function<? super T, ? extends Stream<? extends U>> mapper,
Collector<? super U, A, R> downstream) {
BiConsumer<A, ? super U> acc = downstream.accumulator();
return Collector.of(downstream.supplier(),
(a, t) -> {
try (Stream<? extends U> s = mapper.apply(t)) {
if (s != null) s.forEachOrdered(u -> acc.accept(a, u));
}
},
downstream.combiner(), downstream.finisher(),
downstream.characteristics().toArray(new Collector.Characteristics[0]));
}
あなたはありますJavaの9で[ 'Collectors.flatMapping()'](http://download.java.net/java/jdk9/グループの下流に結果をフラット化するための、docs/api/java/util/stream/Collectors.html#flatMapping-java.util.function.Function-java.util.stream.Collector-)を使用します。 – shmosel