2
Random rand = new Random();
Observable<Integer> random1 = Observable.just(rand.nextInt());
Observable<Integer> random2 = random1.flatMap(r1->Observable.just(r1 * rand.nextInt()));
random2.subscribe(System.out::println);

The above code is just taking a couple of random numbers, multiplying them together, and printing the output.

Here's my question: At the time that I print out the result, is there an elegant way I can get hold of the first random value? Please note that my actual system is making asynchronous calls, not just producing random numbers.

Here are some examples of what I would not consider elegant:

Random rand = new Random();
Observable<Integer> random1 = Observable.just(rand.nextInt());
random1.subscribe(r1->{
  Observable<Integer> random2 = Observable.just(r1 * rand.nextInt());
  random2.subscribe(r2->{
    System.out.println(r1);
    System.out.println(r2);
  });
});

.

Random rand = new Random();
Observable<Integer> random1 = Observable.just(rand.nextInt());
Observable<int[]> result = random1.flatMap(r1->{
  int[] pair = new int[2];
  pair[0] = r1;
  pair[1] = r1 * rand.nextInt();
  return Observable.just(pair);
});
result.subscribe(pair-> {
  System.out.println(pair[0]);
  System.out.println(pair[1]);
});

.

Random rand = new Random();
int[] hack = new int[1];
Observable<Integer> random1 = Observable.just(rand.nextInt()).doOnNext(r1->hack[0]=r1);
Observable<Integer> random2 = random1.flatMap(r1->Observable.just(r1 * rand.nextInt()));
random2.subscribe(r2->{
  System.out.println(hack[0]);
  System.out.println(r2);
});

And, finally, there's this, which I'm not sure is good practice:

Random rand = new Random();
Observable<Integer> random1 = Observable.just(rand.nextInt());
Observable<Integer> random2 = random1.flatMap(r1->Observable.just(r1 * rand.nextInt()));
random2.subscribe(r2-> System.out.println(random1.toBlocking().first()));
Rob Worsnop
  • 1,164
  • 1
  • 9
  • 22

3 Answers3

1

Short answer: no.

Your cleanest option is likely to build a class to "wrap" your input and pass it along the chain (or use some sort of tuple class).

Your third example, where you pass along an int[] pair is the closest:

Random rand = new Random();
Observable.just(rand.nextInt())
  .flatMap(r1->{
    int[] pair = new int[2];
    pair[0] = r1;
    pair[1] = r1 * rand.nextInt();
    return Observable.just(pair);
  })
  .subscribe(pair-> {
    System.out.println(pair[0]);
    System.out.println(pair[1]);
  });

This question is similar, and worth a look - it appears to indicate that your first method (nesting observables in order to gain access to the outer observables input) is best. This could result in some fairly deep nesting if you have more than one level up the chain that you care about, though.

Community
  • 1
  • 1
Adam S
  • 16,144
  • 6
  • 54
  • 81
1

There is a flatMap overload that lets you specifiy a Func2 that receives the source value and each value from the Observable being flattened for it:

Random rand = new Random();
Observable<Integer> random1 = Observable.just(rand.nextInt());
Observable<List<Integer>> random2 = random1.flatMap(
    r1 -> Observable.just(r1 * rand.nextInt()),
    (r1, r2) -> Arrays.asList(r1, r2));

random2.subscribe(System.out::println);
akarnokd
  • 69,132
  • 14
  • 157
  • 192
0

How about zip operator?

Random rand = new Random();
Observable<Integer> random1 = Observable.just(rand.nextInt());
Observable<Integer> random2 = Observable.just(rand.nextInt());

random1.zipWith(random2, Pair::new).subscribe(System.out::println);
krp
  • 2,247
  • 17
  • 14
  • The two random numbers aren't being multiplied in this example. I included that because my actual use case has the second observable depending on the first. – Rob Worsnop Feb 14 '15 at 18:53