Skip to content

Add Seq.reducingMap() and Seq.reducePartially() methods #338

@tlinkowski

Description

@tlinkowski

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:

  1. reducePartially works like Stream.reduce(BinaryOperator), only it yields and restarts the reduction if conditionalAccumulator returns an empty Optional:
  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).

  1. reducingMap works like Stream.reduce(U, BiFunction, BinaryOperator), only it yields and restarts the reduction if conditionalAccumulator returns an empty Optional, and it has a different mechanism for providing initial Us (instead of U identity we have an initialMapper that converts the first T to the initial U):
  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:

  1. 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"
  1. 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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions