执行groupBy操作后如何将多个对象合并为一个对象?

时间:2017-11-19 19:00:20

标签: android rx-java reactive-programming rx-android rx-java2

我有下面的课程,我已经创建,以说明我的疑问。

在我的可流动的初始变换后,我有:

UserScoreTO{id=1, name='john', score=4}
UserScoreTO{id=1, name='john', score=5}
UserScoreTO{id=1, name='john', score=1}
UserScoreTO{id=2, name='paul', score=4}
UserScoreTO{id=2, name='paul', score=2}
UserScoreTO{id=3, name='mark', score=1}
UserScoreTO{id=3, name='mark', score=7}

我希望将具有相同ID的UserScoreTO对象组合到一个Flowable中,为每个组发出一个单独的对象,其中包含用户信息和分数总和。

因此结果将是可流动的,发出:

User (1, "john", 10);
User (2, "paul", 6);
User (3, "mark", 8);

如果可能的话,我想用RxJava做这个(我知道我可以用HashMaps做同样的事情)。

package examples.rxjava;

import java.util.Arrays;
import java.util.List;

import io.reactivex.Flowable;

import static java.lang.System.out;

public class TestUsers {

    public static void main(String[] args) {
        new TestUsers().execute();
    }


    public void execute() {
        getUsers()
                .flatMap(list -> Flowable.fromIterable(list))
                .groupBy(userScoreTO -> userScoreTO.id).subscribe(group -> group.subscribe(out::println));

    }





    Flowable<List<UserScoreTO>> getUsers() {
        return Flowable.fromCallable(
                () -> Arrays.asList(
                        new UserScoreTO(1, "john", 4),
                        new UserScoreTO(1, "john", 5),
                        new UserScoreTO(1, "john", 1),

                        new UserScoreTO(2, "paul", 4),
                        new UserScoreTO(2, "paul", 2),

                        new UserScoreTO(3, "mark", 1),
                        new UserScoreTO(3, "mark", 7))
        );


    }

    private class User {
        private int id;
        private String name;
        private int totalScore;

        public User(int id, String name, int totalScore) {
            this.id = id;
            this.name = name;
            this.totalScore = totalScore;
        }

        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", totalScore=" + totalScore +
                    '}';
        }
    }

    private class UserScoreTO {
        private int id;
        private String name;
        private int score;


        public UserScoreTO(int id, String name, int score) {
            this.id = id;
            this.name = name;
            this.score = score;
        }

        @Override
        public String toString() {
            return "UserScoreTO{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", score=" + score +
                    '}';
        }
    }

}

2 个答案:

答案 0 :(得分:1)

您提供的代码已经完全符合您的要求。 groupBy会将具有相同id的UserScoreTO对象分组到同一个GroupedFlowable对象中。

修改

好的,我知道,也许以下内容可以做得更好一点

  public void execute() {
getUsers()
    .flatMap(Flowable::fromIterable)
    .groupBy(userScoreTO -> userScoreTO.id)
    .map(group -> group.reduce(new User(group.getKey(), "", 0),
        (user, userScoreTO) -> {
          user.name = userScoreTO.name;
          user.totalScore += userScoreTO.score;
          return user;
        }))
    .subscribe(userSingle -> userSingle.subscribe(System.out::println));

}

您想要的是通过应用reduce运算符将UserScoreTo聚合到同一个User对象中。

答案 1 :(得分:1)

在做了一些研究并做了大量的试错代码后,我发现这个[collect][1]运算符可以解决问题:

它创建一个新的User对象(User::new)作为初始供应商,该供应商保存来自组中所有项目的数据。所以我设置属性并增加分数,在组迭代结束时返回它。

由于我是RxJava的新手,我不知道这是否是最好的方法,或者代码是否可以简化,但结果代码是:

getUsers()
                .flatMap(list -> Flowable.fromIterable(list))
                .groupBy(userScoreTO -> userScoreTO.id)
                .flatMap(groups -> Flowable.fromCallable(() -> groups.collect(User::new, (user, userscore) -> {
                    user.id = userscore.id;
                    user.name = userscore.name;
                    user.totalScore += userscore.score;
                }))).subscribe(userSingle -> {
            userSingle.subscribe(new SingleObserver<User>() {
                @Override
                public void onSubscribe(Disposable d) {
                    System.out.println("onSubscribe");
                }

                @Override
                public void onSuccess(User user) {
                    System.out.println(user);
                }

                @Override
                public void onError(Throwable e) {
                    System.out.println(e);

                }
            });

        });

输出:

onSubscribe
onSubscribe
onSubscribe
User{id=1, name='john', totalScore=10}
User{id=2, name='paul', totalScore=6}
User{id=3, name='mark', totalScore=8}