Split a flux into two fluxes - head and tail

亡梦爱人 提交于 2021-02-19 02:18:37

问题


I want to split a flux into two fluxes where the first one has the first item of the original flux and the second one will takes the rest of items.

After applying a custom transformation myLogic on each flux I want to combine them into one flux preserving the order of the original flux.

Example:

S: student
S': student after applying myLogic

Emitted flux: s1 -> s2 -> s3 -> s4
The first splited flux: s1' => myLogic
The second splited flux: s2' -> s3' -> s4' => myLogic
The combined flux: s1' -> s2' -> s3' -> s4'


回答1:


It is enough to use standard Flux methods take and skip to seprate head and tail elements. Calling cache before that is also useful to avoid subscription duplication.

class Util {

  static <T, V> Flux<V> dualTransform(
    Flux<T> originalFlux,
    int cutpointIndex,
    Function<T, V> transformHead,
    Function<T, V> transformTail
  ) {
    var cached = originalFlux.cache();
    var head = cached.take(cutpointIndex).map(transformHead);
    var tail = cached.skip(cutpointIndex).map(transformTail);

    return Flux.concat(head, tail);
  }

  static void test() {
    var sample = Flux.just("a", "b", "c", "d");

    var result = dualTransform(
                   sample,
                   1, 
                   x -> "{" + x.toUpperCase() + "}", 
                   x -> "(" + x + ")"
                 );

    result.doOnNext(System.out::print).subscribe();

    // prints: {A}(b)(c)(d)
  }
}



回答2:


There's a more simple solution to your problem. You don't need to split and merge the events from publisher. You can make use of index(). It keeps information about the order in which events are published.

Flux<String> values = Flux.just("s1", "s2", "s3");
values.index((i, v) -> {
  if (i == 0) {
    return v.toUpperCase();
  } else {
    return v.toLowerCase();
  }
});



回答3:


Here's a hacky way to do this:

boolean a[] = new boolean[]{false};  //use an array as you cannot use non-final variables inside lambdas

    originalFlux
        .flatMap(a -> {
            if(!a[0]) {
                a[0] = true;
                return runLogicForFirst(a);
            } else {
                return runLogicForRest(a);
            }
        })



回答4:


Instead of creating two separate Flux objects and then merging them, you can just zip your original Flux with another Flux<Boolean> that's only ever true on the first element.

You can then do your processing conditionally as you please in a normal map() call without having to merge separate publishers later on:

Flux<String> values = Flux.just("A", "B", "C", "D", "E", "F", "G");

Flux.zip(Flux.concat(Flux.just(true), Flux.just(false).repeat()), values)
        .map(x -> x.getT1() ? "_"+x.getT2().toUpperCase()+"_" : x.getT2().toLowerCase())
        .subscribe(System.out::print);    // prints "_A_bcdefg"


来源:https://stackoverflow.com/questions/58696866/split-a-flux-into-two-fluxes-head-and-tail

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!