web-dev-qa-db-fra.com

RxJava: Comment convertir une liste d'objets en une liste d'autres objets

J'ai la liste de SourceObjects et j'ai besoin de la convertir en liste de ResultObjects.

Je peux aller d'un objet à un autre en utilisant la méthode de ResultObject:

convertFromSource(srcObj);

bien sûr je peux le faire comme ça:

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

mais je serai très reconnaissant à quelqu'un qui peut montrer comment faire de même avec rxJava .

46
Yura Buyaroff

Si votre Observable émet une List, vous pouvez utiliser ces opérateurs:

  • flatMapIterable (transformer votre liste en un observable d'éléments)
  • map (transformer votre article en un autre article) 
  • toList opérateurs (transforme un observable complété en un observable qui émet une liste d'éléments de l'observable terminé)

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

Si vous voulez conserver la Lists émise par la source Observable mais convertir le contenu, c'est-à-dire Observable<List<SourceObject>> en Observable<List<ResultsObject>>, vous pouvez procéder de la manière suivante:

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 -> ...);

Cela garantit un certain nombre de choses:

  • Le nombre de Lists émis par Observable est maintenu. c'est-à-dire si la source émet 3 listes, il y aura 3 listes transformées à l'autre bout
  • Utiliser Observable.fromIterable() assurera que la Observable intérieure se termine de sorte que toList() puisse être utilisé
40
Noel

La méthode Observable.from () factory vous permet de convertir une collection d'objets en un flux Observable. Une fois que vous avez un flux, vous pouvez utiliser l’opérateur map pour transformer chaque élément émis. Enfin, vous devrez vous abonner à l'observable résultant pour pouvoir utiliser les éléments transformés:

// 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
    }
});

La version abrégée si vous utilisez lambdas ressemblerait à ceci:

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

Ne casse pas la chaîne, juste comme ça.

Observable.from(Arrays.asList(new String[] {"1", "2", "3", }))
.map(s -> Integer.valueOf(s))
.reduce(new ArrayList<Integer>, (list, s) -> {
    list.add(s);
    return list;
})
.subscribe(i -> {
    // Do some thing with 'i', it's a list of Integer.
});
4
AtanL

Si vous avez simplement besoin de List<A> à List<B> sans manipuler le résultat de List<B>.

La version la plus propre est:

List<A> a = ... // ["1", "2", ..]
List<B> b = Observable.from(a)
                      .map(a -> new B(a))
                      .toList()
                      .toBlocking()
                      .single();
0
saiday

En prolongement de Noel excellente réponse. Supposons que la transformation dépende également de certaines données du serveur susceptibles de changer au cours de la souscription. Dans ce cas, utilisez flatMap + scan.

En conséquence, lorsque la liste d'identificateurs est modifiée, les transformations redémarrent. Et lorsque les données du serveur changent en fonction d'un identifiant spécifique, un seul élément est également retransformé. 

fun getFarmsWithGroves(): Observable<List<FarmWithGroves>> {

        return subscribeForIds() //may change during subscription
                .switchMap { idList: Set<String> ->

                    Observable.fromIterable(idList)
                            .flatMap { id: String -> transformId(id) } //may change during subscription
                            .scan(emptyList<FarmWithGroves>()) { collector: List<FarmWithGroves>, candidate: FarmWithGroves ->
                                updateList(collector, candidate)
                            }
                }
    }
0
Andrew