For each in list, do operation until condition is met

Viewed 116

Consider the following code:

void tryToOpenSafe() {
    getCorrectSafeCombination().subscribe(combination -> System.out.println("Correct combination is " + combination));
}

Maybe<Integer> getCorrectSafeCombination() {
    return getPossibleCombinations()
            .toObservable()
            .flatMapIterable(combinations -> combinations)
            .flatMap(combination -> tryToOpenSafeWithCombination(combination).toObservable()
                    .map(isCorrect -> new CombinationCheckResult(combination, isCorrect)))
            .filter(result -> result.isCorrect)
            .map(result -> result.combination)
            .firstElement();

}

Single<List<Integer>> getPossibleCombinations() {
    final List<Integer> combinations = Arrays.asList(123, 456, 789, 321);
    return Single.just(combinations);
}

// this is expensive
final Single<Boolean> tryToOpenSafeWithCombination(int combination) {
    System.out.println("Trying to open safe with " + combination);
    final boolean isCorrectCombination = combination == 789;
    return Single.just(isCorrectCombination);
}

I receive a list of possible "combinations" (integer) for a safe I want to open. Only one combination is the correct one of course.

With my current approach, getCorrectSafeCombination() will deliver the first correct combination it found; but it will try all the combinations nonetheless.

This is in efficient though: as soon as the correct combination is found, there is no need to try the others.

How can this be done with Rx?

1 Answers

This happens because flatMap is used for concurrent processing of observables while you need sequential. To fix that you just need to change your flatMap to concatMap to ensure sequential flow of observables in your getCorrectSafeCombination method:

Maybe<Integer> getCorrectSafeCombination() {
    return getPossibleCombinations()
            .toObservable()
            .flatMapIterable(combinations -> combinations)
            //this one
            .concatMap(combination -> tryToOpenSafeWithCombination(combination).toObservable()
                    .map(isCorrect -> new CombinationCheckResult(combination, isCorrect)))
            .filter(result -> result.isCorrect)
            .map(result -> result.combination)
            .firstElement();

}
Related