Tima
Tima

Reputation: 12915

RxJava2. Process different properties of the object from the list

Assume

  1. There is a class User with two properties name and age
  2. We get a list of users
  3. We need to process both properties of every user.

Is it possible at all to process both properties of every user?

The following code is not correct, I know. but how to make it correct? Maybe there are any operators to get it work?

Observable.fromIterable(users)
    .map(user -> user.name)
    .map(string -> new NameVM(string))
    .map(user -> user.age)
    .map(int -> new AgeVM(int))

I have only one idea, but I don't like it much

Observable.fromIterable(users)
    .doOnNext(user -> new NameVM(string))
    .map(user -> user.age)
    .map(int -> new AgeVM(int))

Upvotes: 1

Views: 467

Answers (3)

Tima
Tima

Reputation: 12915

I ended up with a container solution

class ContainerVM {
    public NameVM nameVM;
    public AgeVM ageVM;
}

Observable.fromIterable(users)
    .map(user -> buildContainerVM(user));

private ContainerVM buildContainerVM(User user) {
    ContainerVM containerVM = new ContainerVM();
    containerVM.nameVM = new NameVM(user.name);
    containerVM.ageVM = new AgeVM(user.age);
}

Upvotes: 0

Sergej Isbrecht
Sergej Isbrecht

Reputation: 4012

You could just process both properties as Singles and zip the result together and flatMap it with flatMapSingle. In doOnNext you would a Container for each zip.

@Test
  void name2() throws Exception {
    List<User> users =
        Arrays.asList(
            new User("hans", 30), new User("leon", 66), new User("Uwe", 45), new User("Michi", 23));

    Observable<Container> containerObservable =
        Observable.fromIterable(users)
            .flatMapSingle(
                user -> {
                  Single<ProcessedAge> processedAgeSingle = processeAge(user.age);
                  Single<ProcessedUserName> processedUserNameSingle =
                      processeUserName(user.userName);

                  return Single.zip(
                      processedAgeSingle,
                      processedUserNameSingle,
                      (age, name) -> {
                        return new Container(age, name);
                      });
                })
            .doOnNext(System.out::println);

    containerObservable.test().await().assertValueCount(4);
  }

  private Single<ProcessedAge> processeAge(int age) {
    return Single.just(new ProcessedAge());
  }

  private Single<ProcessedUserName> processeUserName(String userName) {
    return Single.just(new ProcessedUserName());
  }

  class User {
    String userName;
    int age;

    public User(String userName, int age) {
      this.userName = userName;
      this.age = age;
    }
  }

  class ProcessedUserName {}

  class ProcessedAge {}

  class Container {
    ProcessedUserName userNameResult;
    ProcessedAge ageResult;

    public Container(ProcessedAge age, ProcessedUserName name) {
      this.userNameResult = name;
      this.ageResult = age;
    }

    @Override
    public String toString() {
      return "Container{" + "userNameResult=" + userNameResult + ", ageResult=" + ageResult + '}';
    }
  }

Upvotes: 1

Sarath Kn
Sarath Kn

Reputation: 2745

I'm not sure what are you trying to do , but from the question I think you have an observable of list of users and you need to process name and age of every user and finally consume the updated user data. For this why can't you use a single map operator

        Observable.fromIterable(users)
            .map(user -> {
                user.name =//do something with name);
                user.age = // do something with age);
                return user;
            }).subscribe(user -> {
                // here you get the result with processed user object
            });

Upvotes: 0

Related Questions