【问题标题】:rxJava transform List to MaprxJava 将 List 转换为 Map
【发布时间】:2015-11-20 02:16:41
【问题描述】:

我有从 REST 端点返回的列表。我需要将该列表分解为类别(类别是列表每个条目中的一个项目)。个别类别将被写入缓存,以便以后更快地查找。

我不知道我是否可以 .map() 条目并提供多个 filter() 或某种类型的 case 语句来将类别条目放入正确的存储桶中。

用 rxJava 实现这样的事情听起来合理吗?

更新: 非工作版本

private Map<String, List<VideoMetadataInfoEntity>> buildCategories( Observable<List<VideoMetadataInfoEntity>> videoList ) {

    Map<String, List<VideoMetadataInfoEntity>> categoryMap = new HashMap<>();
    videoList
            .flatMap( Observable::from )
            .subscribe( videoMetadataInfoEntity -> mapCategory(videoMetadataInfoEntity, categoryMap ) );

    Observable.just( categoryMap )
            .doOnNext( saveCategoriesToCacheAction );

    return categoryMap;
}

然而,这些按顺序触发,这是我的理解,第二个 observable 没有发送任何 saveCategoriesToCacheAction 内容,因为它没有订阅第一个 observable 的结果。

我开始认为我应该修改我的缓存策略。该列表将始终包含所有详细信息。该服务没有为我提供可用于列出的子集,然后再次调用以获取完整详细信息。它是一个项目的完整列表或完整详细信息。现在将每个单独缓存到他们自己的类别缓存中可能是一种更好的方法。我试图做映射,以便此网络调用可以返回请求的类别,但后续调用将来自缓存,直到缓存过期并且新的网络调用刷新它。

【问题讨论】:

  • rx 适用于您希望并行执行任务的地方。这里的并行性在哪里?

标签: android rx-java


【解决方案1】:

我的解决办法是:

Observable.range(1, 20)
            .groupBy(number -> number % 2)
            .flatMap(groupedObservable -> groupedObservable.toList())
            .toMap(list -> list.get(0) % 2);

结果我有[{0=[2, 4, 6, 8, 10, 12, 14, 16, 18, 20], 1=[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]}]

解释:

  • range(1, 20) - 创建一个发出前 20 个数字的 observable
  • groupBy(number -> number % 2) - 创建一个 observable,它发出组 observables,其中每个组 observable 包含使用分组函数分组的项目(这里是 x % 2)
  • flatMap(groupedObservable -> groupedObservable.toList()) - 将每个组变成一个可观察对象,将其所有项目作为列表发出
  • toMap(list -> list.get(0) % 2) - 创建地图

【讨论】:

    【解决方案2】:

    RxJava 更多用于异步消息处理,但由于它也支持函数式编程原则,因此可以用作穷人的流 api。如果您使用的是 Java 8,请考虑使用流来完成这项工作,但是当您提出这个问题时,我假设您使用的是 Java 7。

    您可以尝试做您想做的事(原谅 lambda,如果您不使用 Retrolambda,请用匿名内部类替换它):

    Observable.from(list).subscribe(item -> groupItemInCategoryBucket(item));
    

    groupItemInCategoryBucket 是您的方法,其中包含 switch 语句或任何其他缓存项目的方式。

    请注意,这相当于一个 for 循环,虽然在许多其他不错的语言中使用这种风格是惯用的,但很多 Java 开发人员在看到这段代码时可能会有些困惑。

    【讨论】:

    • 我正在使用retrolambda,它是java7。这将在一个 android 应用程序中。我会试试这个。我需要对各个类别执行一些其他任务,例如将其转储到磁盘和内存缓存中,以便它不会经常通过网络调用。我希望我可以干净利落地构建这条链,或者通过其他订阅。在某些情况下,只需要列表,在其他情况下,需要类别组。类似的东西。谢谢。
    • 不客气。希望它会成功;如果没有,请更新您的问题,提供有关您要执行的其他操作的更具体的详细信息,以便我的回答更有帮助。
    • 我更新了我的问题。我想我需要改变我的方法。
    • 第二个 observable 没有被订阅,所以它不会做任何事情。尝试在第二个 observable 上调用 .subscribe()。
    【解决方案3】:

    通常可以使用 groupBy 运算符对项目进行分组(有关它的更多信息,请访问this page)。

    Map<Integer, List<Integer>> groupedValues = new HashMap<>(4);
        Observable.range(1, 20)
                .groupBy(i -> i % 2, i -> i)
                .subscribe(go -> {
                    List<Integer> groupValues = new ArrayList<>();
                    groupedValues.put(go.getKey(), groupValues);
                    go.subscribe(t -> add(t, groupValues));
                });
    

    工作原理:

  • 首先,observable 发出项目 1 到 20(这发生在 range 方法中)
  • 然后根据它们的 parity(groupBy方法,这个方法之后你操作GroupedObservable)
  • 然后,您订阅分组的 observable,接收(在订阅者 onNext 中)单独的 observable,其中将包含分组项目及其分组依据。
  • 如果您对它们的内容不感兴趣,请记住订阅分组的 observables 或在其上发出 take(0) 以防止内存泄漏。

    我不确定这是否是最有效的方式,并欢迎对此解决方案提供一些意见。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-23
      • 1970-01-01
      • 2017-07-14
      • 1970-01-01
      • 2022-09-30
      • 2021-02-28
      相关资源
      最近更新 更多