RxDart,将列表中的每个项目映射到来自永不结束的流的另一个对象

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RxDart,将列表中的每个项目映射到来自永不结束的流的另一个对象相关的知识,希望对你有一定的参考价值。

我一直试图找到一个很好的方法,但我没有运气。

以下是问题的简化版本:

import 'package:rxdart/rxdart.dart';


/// Input a list of integers [0,1,2,3,4]
/// map each of those integers to the corresponding index in the map
/// if the map updates, the output should update too.
///
/// The output should be a list of Strings:
/// ["Hi from 1", "Hi from 2"; "Hi from 3", "Hi from 4", "Hi from 5"]
BehaviorSubject<Map<int, String>> subject = BehaviorSubject(
    seedValue: {
      1: "Hi from 1",
      2: "Hi from 2",
      3: "Hi from 3",
      4: "Hi from 4",
      5: "Hi from 5",
    }
);

void main() {
  Observable.fromIterable([1, 2, 3, 4, 5])
      .flatMap((index) => subject.stream.map((map) => map[index]))
      .toList().asObservable()
      .listen((data) {
    print("List of data incoming $data");
  });
}

运行时,不会打印任何内容。这是因为主题永远不会完成,因此toList()永远不会完成列表的构建。

用例如Observable.just(index + 2)替换主题确实有效,因为Observable完成并且toList()能够收集它们。

但是,预期的行为是每次更改主题时,示例都应发出新的字符串列表。

任何帮助,将不胜感激,

谢谢!

答案

你可能想用combineLatest代替

BehaviorSubject<Map<int, String>> subject = BehaviorSubject(seedValue: {
  1: "Hi from 1",
  2: "Hi from 2",
  3: "Hi from 3",
  4: "Hi from 4",
  5: "Hi from 5",
});

void main() {
  Observable.combineLatest2(
      Observable.just([1, 2, 3, 4, 5]), subject.stream, combiner)
    ..listen(
      (data) {
        print("List of data incoming $data");
      },
    );
}

Iterable<String> combiner(List<int> indexes, Map<int, String> map) {
  return indexes.map((index) => map[index]);
}
另一答案

编辑:发布后不久,我意识到这完全取决于数据的公开方式:

如果你有一个像Observable<String> getStringForInt(int number)这样的签名的方法,你必须为列表中的每个项目调用它,我的解决方案就是你的解决方案。请注意,如果上述方法始终订阅同一个流,则更改该流将导致多个发射(因为combineLatest会更新每个项目)。

但是,如果您可以访问整个数据容器(如Map)

原始答案

好吧,事实证明,通过实现rxDart实现这一目标是不可能的。

combineLatest构造函数最多只支持9个流。

但从那时起,combineLatest与n-streams已经实现,这个问题的解决方案看起来像这样:

Map<int, BehaviorSubject<String>> subject2 = {
  1: BehaviorSubject<String>(seedValue: "Subject 1"),
  2: BehaviorSubject<String>(seedValue: "Subject 2"),
  3: BehaviorSubject<String>(seedValue: "Subject 3"),
  4: BehaviorSubject<String>(seedValue: "Subject 4"),
  5: BehaviorSubject<String>(seedValue: "Subject 5"),
};

void main() async {

  Observable.fromIterable([1, 2, 3, 4, 5])
      .toList().asObservable()
      .flatMap((numbers) =>
      Observable.combineLatest<String, List<String>>(numbers.map((index) => subject2[index]), (strings) => strings))
      .listen((data) {
    print("List of data incoming $data");
  });

  await Future.delayed(Duration(seconds: 2));
  subject2[1].add("I'm 42 now");
}

这将打印:

List of data incoming [Subject 1, Subject 2, Subject 3, Subject 4, Subject 5]
List of data incoming [I'm 42 now, Subject 2, Subject 3, Subject 4, Subject 5]

以上是关于RxDart,将列表中的每个项目映射到来自永不结束的流的另一个对象的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 中的 rxdart 使用未被识别

将每个列表值映射到其相应的百分位数

将 Json 响应中的对象列表映射到颤动中的列表

来自 True 值范围(开始和结束)的布尔列表,不使用 for 循环

将整数映射到组合框中的自定义类的字符串

如何使用算法将一种类型的列表映射到现代 C++ 中的另一种类型的列表