RxJava compare different items from two observables (java 7)

mir :

I have two Observables ob1 & ob2 that emit items . If ob1.item is contained in ob2 I want to ignore it.

Example :

ob1 contains A,B,C,D

ob2 contains E,C,B,G,J,O

output :

ob contains A,D

What is the best way to express this ?

Lamorak :

There is a contains operator which returns Observable<Boolean> for whether observable contains given element.

Observable<Boolean> contains = observable2.contains(string);

What you need is to map all elements from observable1 to those boolean observables

observable1.map(new Func1<String, Observable<Boolean>>() {
    @Override
    public Observable<Boolean> call(final String string) {
        return observable2.contains(string);
    }
})

This would give you Observable<Observable<Boolean>>, but it would be hard to work with this. Therefore you concatenate all those boolean observables into one. Luckilly, all you need to do for that is to use concatMap instead of map

observable1.concatMap(new Func1<String, Observable<Boolean>>() {
    @Override
    public Observable<Boolean> call(final String string) {
        return observable2.contains(string);
    }
})

Now you have an observable1 that contains your elements and an Observable<Boolean> that contains boolean for whether the element in observable1 is contained in observable2

observable1:            A ---- B ---- C ---- D
concatMapObservable:    false  true   true   false

You can easily zip those two observables into an observable which will pass the elements that are not contained in observable2 and replace others with an empty string

[concatMapObservable].zipWith(observable1, new Func2<Boolean, String, String>() {
    @Override
    public String call(final Boolean contains, final String string) {
        return contains ? "" : string;
    }
}

Then you filter the empty strings

[zippedObservable].filter(new Func1<String, Boolean>() {
    @Override
    public Boolean call(final String string) {
        return !TextUtils.isEmpty(string);
    }
})

The whole code put together:

Observable<String> observable1 = Observable.from(new String[]{"A", "B", "C", "D"});
Observable<String> observable2 = Observable.from(new String[]{"E", "C", "B", "G", "J", "O"});

observable1.concatMap(new Func1<String, Observable<Boolean>>() {
    @Override
    public Observable<Boolean> call(final String string) {
        return observable2.contains(string);
    }
}).zipWith(observable1, new Func2<Boolean, String, String>() {
    @Override
    public String call(final Boolean contains, final String string) {
        return contains ? "" : string;
    }
}).filter(new Func1<String, Boolean>() {
    @Override
    public Boolean call(final String string) {
        return !TextUtils.isEmpty(string);
    }
}).subscribe(new Action1<String>() {
    @Override
    public void call(final String string) {
        Log.d("observable:", string);
    }
});

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=475984&siteId=1