web-dev-qa-db-ja.com

RxJava:オブジェクトのリストを別のオブジェクトのリストに変換する方法

SourceObjectsのリストがあり、それをResultObjectsのリストに変換する必要があります。

ResultObjectのメソッドを使用して、あるオブジェクトを別のオブジェクトにフェッチできます。

convertFromSource(srcObj);

もちろん次のようにできます:

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

しかし、rxJavaを使用して同じことを行う方法を示すことができる人には非常に感謝しています。

51
Yura Buyaroff

ObservableListを出力する場合、次の演算子を使用できます。

  • flatMapIterable(リストをObservable of itemsに変換します)
  • map(アイテムを別のアイテムに変換)
  • toList演算子(完成したObservableを、完成したObservableからアイテムのリストを出力するObservableに変換します)

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

ソースListsから発行されたObservableを維持したいが、内容、つまりObservable<List<SourceObject>>Observable<List<ResultsObject>>に変換したい場合は、次のようにすることができます。

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

これにより、いくつかのことが保証されます。

  • Listsから放出されるObservableの数は維持されます。つまり、ソースが3つのリストを発行する場合、もう一方の端には3つの変換されたリストがあります
  • Observable.fromIterable()を使用すると、toList()を使用できるように、内側のObservableが終了することが保証されます。
52
Noel

Observable.from() factoryメソッドを使用すると、オブジェクトのコレクションをObservableストリームに変換できます。ストリームを取得したら、 map 演算子を使用して、放出された各アイテムを変換できます。最後に、変換されたアイテムを使用するには、結果のObservableをサブスクライブする必要があります。

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

ラムダを使用する場合の短縮バージョンは次のようになります。

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

このように、チェーンを壊さないでください。

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

必要なものがList<A>の結果を操作せずに、単にList<B>からList<B>である場合。

最もクリーンなバージョンは次のとおりです。

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

Noel への拡張として。変換は、サブスクリプション中に変更される可能性のある一部のサーバーデータにも依存するとします。その場合、flatMap+scanを使用します。

その結果、IDリストが変更されると、変換が新たに再開されます。また、特定のIDに関連するサーバーデータが変更されると、単一のアイテムも再変換されます。

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

ネストされたマップ関数を使用した非ブロック変換

val ints: Observable<List<Int>> = Observable.fromArray(listOf(1, 2, 3))

val strings: Observable<List<String>> = ints.map { list -> list.map { it.toString() } }
0
tomrozb