简体   繁体   English

RxJava:如何将对象列表转换为另一个对象的列表

[英]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.我有 SourceObjects 列表,我需要将它转换为 ResultObjects 列表。

I can fetch one object to another using method of ResultObject:我可以使用 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 .但我将非常感谢可以展示如何使用rxJava做同样事情的人

If your Observable emits a List , you can use these operators:如果您的Observable发出一个List ,您可以使用这些运算符:

  • flatMapIterable (transform your list to an Observable of items) flatMapIterable (将您的列表转换为一个 Observable 项目)
  • map (transform your item to another item) map (将您的项目转换为另一个项目)
  • toList operators (transform a completed Observable to a Observable which emit a list of items from the completed Observable) toList操作符(将一个完整的 Observable 转换为一个 Observable,它从完整的 Observable 发出一个项目列表)

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

If you want to maintain the Lists emitted by the source Observable but convert the contents, ie Observable<List<SourceObject>> to Observable<List<ResultsObject>> , you can do something like this:如果你想维护源Observable发出的Lists但转换内容,即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 -> ...);

This ensures a couple of things:这确保了几件事:

  • The number of Lists emitted by the Observable is maintained.Observable发出的Lists数量保持不变。 ie if the source emits 3 lists, there will be 3 transformed lists on the other end即如果源发出 3 个列表,则另一端将有 3 个转换后的列表
  • Using Observable.fromIterable() will ensure the inner Observable terminates so that toList() can be used使用Observable.fromIterable()将确保内部Observable终止,以便可以使用toList()

The Observable.from() factory method allows you to convert a collection of objects into an Observable stream. Observable.from()工厂方法允许您将对象集合转换为 Observable 流。 Once you have a stream you can use the map operator to transform each emitted item.一旦你有了一个流,你就可以使用map操作符来转换每个发出的项目。 Finally, you will have to subscribe to the resulting Observable in order to use the transformed items:最后,您必须订阅生成的 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
    }
});

The abbreviated version if you use lambdas would look like this:如果您使用 lambda,则缩写版本如下所示:

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

Don't break the chain, just like this.不要打破链条,就像这样。

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

Non blocking conversion using nested map function使用嵌套映射函数的非阻塞转换

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

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

You can use map operator.您可以使用地图运算符。 For example if you have list s of integers and you want to convert to list s of doubles:例如,如果你有一个整数列表S和要转换到双打的名单S:

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

But all it's a lot more natural if you can control the observable and change it to observe single elements instead of collections.但是,如果您可以控制 observable 并将其更改为观察单个元素而不是集合,那就更自然了。 Same code that converts single integer elements into double ones:将单个整数元素转换为双整数元素的相同代码:

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

As an extension to Noel great answer.作为Noel的扩展很好的答案。 Let's say transformation also depends on some server data that might change during subscription.假设转换还取决于订阅期间可能会更改的某些服务器数据。 In that case use flatMap + scan .在这种情况下,请使用flatMap + scan

As a result when id list changes, transformations will restart anew.因此,当 id 列表更改时,转换将重新开始。 And when server data changes related to a specific id, single item will be retransformed as well.当与特定 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)
                            }
                }
    }

Using toList() waits for the source observable to complete, so if you do that on an infinite observable (like one bound to UI events and Database calls), you will never get anything in your subscribe().使用 toList() 等待源 observable 完成,所以如果你在无限的 observable 上这样做(比如绑定到 UI 事件和数据库调用),你将永远不会在你的 subscribe() 中得到任何东西。

The solution to that is to Use FlatMapSingle or SwitchMapSingle .解决方案是使用FlatMapSingleSwitchMapSingle

Observable<List<Note>> observable =   noteDao.getAllNotes().flatMapSingle(list -> Observable.fromIterable(list).toList());

Now,everytime your list is updated, you can make that event behave as an observable.现在,每次更新您的列表时,您都可以使该事件表现为可观察的。

If what you need is simply List<A> to List<B> without manipulating result of List<B> .如果您需要的只是List<A>List<B>而不操作List<B>

The cleanest version is:最干净的版本是:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM