Подтвердить что ты не робот

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.

4b9b3361

Ответ 1

Если ваш Observable испускает List, вы можете использовать следующие операторы:

  • flatMapIterable (преобразуйте список в наблюдаемый элемент)
  • map (преобразуйте свой элемент в другой элемент) Операторы
  • toList (преобразование завершенного наблюдаемого в наблюдаемое, которое испускает список элементов из завершенного Observable)

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

Ответ 2

Если вы хотите сохранить 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() гарантирует, что внутренний Observable завершается так, что toList() можно использовать

Ответ 3

метод 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
    }
});

Сокращенная версия, если вы используете lambdas, будет выглядеть так:

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

Ответ 4

Не разрушайте цепочку, точно так же.

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 a list of Integer.
});

Ответ 5

Если вам нужно просто 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();

Ответ 6

В качестве дополнения к Ноэлю отличный ответ. Допустим, преобразование также зависит от некоторых данных сервера, которые могут измениться во время подписки. В этом случае используйте flatMap + scan.

В результате при изменении списка идентификаторов преобразования будут перезапущены заново. И когда данные сервера изменяются, связанные с определенным идентификатором, отдельный элемент также будет преобразован.

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

Ответ 7

Вы можете использовать map оператор. Например, если у вас есть список 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;
    });

Но все это намного естественнее, если вы можете контролировать наблюдаемое и изменять его, чтобы наблюдать отдельные элементы вместо коллекций. Тот же код, который преобразует одиночные целые элементы в двойные:

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