2016-03-01 4 views
29

Ho l'elenco di oggetti SourceObjects e ho bisogno di convertirlo nell'elenco di ResultObjects.RxJava: Come convertire un elenco di oggetti in un elenco di altri oggetti

posso prendere un oggetto all'altro metodo che utilizza di ResultObject:

convertFromSource(srcObj); 

Certo che posso farlo in questo modo:

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

ma sarò molto apprezzare a qualcuno che può mostrare come fare lo stesso usando rxJava.

risposta

40

Se il Observable emette un List, è possibile utilizzare questi operatori:

  • flatMapIterable (trasformare la vostra lista di un'osservabile di elementi)
  • map (trasformare la vostra voce ad un altro articolo)
  • toList operatori (trasformare un Osservabile completo in Osservabile che emette un elenco di oggetti dall'osservabile completato)

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

Sembra davvero pulito, ma presenta alcuni svantaggi. 1. Se la sorgente emette più di una lista, saranno tutte appiattite da 'flatMapIterable' in un singolo flusso di oggetti e' toList() 'le raccoglierà in una singola lista. Quindi se ti preoccupi delle emissioni multiple e tienili in liste separate, sfortunatamente perdi questo. 2. 'toList()' aspetta che la sorgente osservabile si completi, quindi se lo fai su un osservabile infinito (come un evento legato agli eventi dell'interfaccia utente), non otterrai mai nulla nel tuo 'subscribe()'. –

+0

@ MarcinKoziński come risolveresti nr. 2? Sto avendo la situazione in cui .toList non restituisce nulla. Grazie –

+2

Penso che tu abbia solo bisogno di usare un approccio diverso. Se stai provando a trasformare ogni elemento di una lista, dovresti semplicemente fare '.map (list ->/* costruisci una nuova lista usando plain old for loop * /)'. Oppure usa un altro approccio per trasformare la tua lista all'interno di '.map()'. Altrimenti potresti usare operatori come '.take (itemCount)' sul tuo infinito osservabile per renderlo finito. Nota che questo ovviamente elimina tutti gli elementi dopo 'itemCount', quindi potrebbe non essere quello che vuoi. –

0

È possibile utilizzare l'operatore map. Per esempio, se si dispone di lista s di interi e si desidera convertire elencare s dei doppi:

List<Integer> li = new ArrayList<>(); 
    Observable.just(li).map(l -> { 
     List<Double> lr = new ArrayList<Double>(); 
     for(Integer e:l) { 
      lr.add(e.doubleValue()); 
     } 
     return lr; 
    }); 

Ma tutto è molto più naturale se è possibile controllare l'osservabile e cambiarlo osservare singolo elementi invece di collezioni. Lo stesso codice che converte i singoli elementi interi in quelle matrimoniali:

Observable.just(1,2,3).map(elem -> elem.doubleValue()) 
+0

Sarebbe non solo '(li)' emettere un singolo elemento (la lista), non tutti gli elementi della lista come 'from (li)'? –

+0

@ cricket_007 Sì, ma come ho capito del problema Yura vuole emettere liste senza elementi della lista (utilizza onNext (Lista)). Come ho detto nella mia risposta, non è il più naturale, ma a volte può essere quello che vuoi. – lujop

11

Il metodo factory Observable.from() consente di convertire un insieme di oggetti in un flusso osservabile. Una volta che hai uno stream puoi usare l'operatore map per trasformare ogni elemento emesso. Infine, si dovrà sottoscrivere la Observable conseguente al fine di utilizzare gli elementi trasformati:

// 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 versione abbreviata, se si utilizza lambda sarebbe simile a questa:

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

Non rompere il catena, proprio come questo.

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. 
}); 
+1

Invece di 'reduce' puoi usare' toList() 'per un codice più pulito. – Anyonymous2324

+0

Grazie mille, toList() è davvero una buona idea. – AtanL

+0

In realtà ci sono problemi con 'toList' come descritto in questo commento sopra. ridurre risolverli http://stackoverflow.com/questions/35734060/rxjava-how-to-convert-list-of-objects-to-list-of-another-objects#comment62270275_35750170 – tasomaniac

20

Se si desidera mantenere la Lists emessa dalla sorgente Observable ma convertire il contenuto, cioè Observable<List<SourceObject>> a Observable<List<ResultsObject>>, si può fare qualcosa di simile:

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

Questo assicura una coppia di cose:

  • Il numero di Lists emesso dallo Observable viene mantenuto. cioèse la sorgente emette 3 liste, ci saranno 3 elenca trasformati sull'altra estremità
  • Uso Observable.fromIterable() garantirà interno Observable termina modo che toList() può essere utilizzato