RxJava: How to convert List of objects to List of another objects

I have the List of SourceObjects and I need to convert it to the List of ResultObjects.

I can fetch one object to another using method of ResultObject:

convertFromSource(srcObj);

of course I can do it like this:

public void onNext(List<SourceObject> srcObjects) {
   List<ResultsObject> resObjects = new ArrayList<>();
   for (SourceObject srcObj : srcObjects) {
       resObjects.add(new ResultsObject().convertFromSource(srcObj));
   }
}

but I will be very appreciate to someone who can show how to do the same using rxJava.


Solution 1:

If your Observable emits a List, you can use these operators:

  • flatMapIterable (transform your list to an Observable of items)
  • map (transform your item to another item)
  • toList operators (transform a completed Observable to a Observable which emit a list of items from the completed Observable)

    Observable<SourceObjet> source = ...
    source.flatMapIterable(list -> list)
          .map(item -> new ResultsObject().convertFromSource(item))
          .toList()
          .subscribe(transformedList -> ...);
    

Solution 2:

If you want to maintain the Lists emitted by the source Observable but convert the contents, i.e. Observable<List<SourceObject>> to Observable<List<ResultsObject>>, you can do something like this:

Observable<List<SourceObject>> source = ...
source.flatMap(list ->
        Observable.fromIterable(list)
            .map(item -> new ResultsObject().convertFromSource(item))
            .toList()
            .toObservable() // Required for RxJava 2.x
    )
    .subscribe(resultsList -> ...);

This ensures a couple of things:

  • The number of Lists emitted by the Observable is maintained. i.e. if the source emits 3 lists, there will be 3 transformed lists on the other end
  • Using Observable.fromIterable() will ensure the inner Observable terminates so that toList() can be used

Solution 3:

The Observable.from() factory method allows you to convert a collection of objects into an Observable stream. Once you have a stream you can use the map operator to transform each emitted item. Finally, you will have to subscribe to the resulting Observable in order to use the transformed items:

// Assuming List<SourceObject> srcObjects
Observable<ResultsObject> resultsObjectObservable = Observable.from(srcObjects).map(new Func1<SourceObject, ResultsObject>() {
    @Override
    public ResultsObject call(SourceObject srcObj) {
        return new ResultsObject().convertFromSource(srcObj);
    }
});

resultsObjectObservable.subscribe(new Action1<ResultsObject>() { // at this point is where the transformation will start
    @Override
    public void call(ResultsObject resultsObject) { // this method will be called after each item has been transformed
        // use each transformed item
    }
});

The abbreviated version if you use lambdas would look like this:

Observable.from(srcObjects)
  .map(srcObj -> new ResultsObject().convertFromSource(srcObj))
  .subscribe(resultsObject -> ...);