-
Notifications
You must be signed in to change notification settings - Fork 172
Description
On several occasions, I've been looking for a method that would be an inverse of Stream.flatMap. I noticed that other people do too - here's an example question on StackOverflow.
However, there are quite many ways to define it (especially the criteria for such an inverse operation). Finally I've decided to stick to the well-understood reduction semantics, and I've come up with the following two method signatures (names to be discussed) that I'd like to propose for Seq:
reducePartiallyworks likeStream.reduce(BinaryOperator), only it yields and restarts the reduction ifconditionalAccumulatorreturns an emptyOptional:
public static Seq<T> reducePartially(BiFunction<? super T, ? super T, Optional<T>> conditionalAccumulator) {
return reducingMap(Function.identity(), conditionalAccumulator);
}
reducePartially is similar to StreamEx.collapse(BiPredicate,BinaryOperator), with the main difference being that the first argument to conditionalAccumulator is the result of previous reduction (exactly as in reduce).
reducingMapworks likeStream.reduce(U, BiFunction, BinaryOperator), only it yields and restarts the reduction ifconditionalAccumulatorreturns an emptyOptional, and it has a different mechanism for providing initialUs (instead ofU identitywe have aninitialMapperthat converts the firstTto the initialU):
public static <U> Seq<U> reducingMap(Function<? super T, ? extends U> initialMapper,
BiFunction<? super U, ? super T, Optional<U>> conditionalAccumulator);
reducingMap bears some resemblance to StreamEx.collapse(BiPredicate,Collector), but - again - it's much more a "reduce" than a "mark" + "merge".
Here are a few examples of how it is supposed to work:
Seq.reducePartially
Example 1: Merge words ending with hyphens with the following word:
- conditional accumulator:
(a, b) -> a.endsWith("-") ? Optional.of(withoutLastChar(a) + b) : Optional.empty(); - input:
"Sample", "hyp-", "hen-", "ated", "text" - output:
"Sample", "hyphenated", "text"
Seq.reducingMap
Example 1: Join integers using a semicolon until 0 occurs:
- initial mapper:
String::valueOf - conditional accumulator:
(String a, int b) -> b != 0 ? Optional.of(a + ";" + b) : Optional.empty(); - input:
7, 8, 0, 1, 5, 7, 8, 0, 3, 1, 7, 9, 0, 0, 5 - output:
"7;8", "0;1;5;7;8", "0;3;1;7;9", "0", "0;5"
I have this implemented (using a custom, lazy Spliterator) so I could provide a PR if the feature gets accepted.