将Stream <Stream <T >>转换为Stream <T>

时间:2019-06-26 10:17:05

标签: dart rxdart

我正在使用rxdart包来处理dart流。我一直在处理一个特殊的问题。

请查看以下虚拟代码:

final userId = BehaviorSubject<String>();

Stream<T> getStream(String uid) {
  // a sample code that returns a stream
  return BehaviorSubject<T>().stream;
}

final Observable<Stream<T>> oops = userId.map((uid) => getStream(uid));

现在,我想将oops变量转换为仅获取Observable<T>

我很难解释清楚。但是,让我尝试。我有一个流A。我将流A的每个输出映射到另一个流B。现在我有了Stream<Stream<B>>-一种 recurrent 流。我只想听听此模式产生的最新价值。我该如何实现?

3 个答案:

答案 0 :(得分:1)

拥有Stream<Stream<Something>>很少见,因此没有明显的支持。

一个原因是,有几种(至少两种)方式将一连串的事物流组合成事物的流。

  1. 您可以依次收听每个流,等待流完成再开始下一个流,然后按顺序发出事件。

  2. 或者您可以在每个新流可用时监听它们,然后尽快从任何流中发出事件。

使用async / await易于编写前者:

Stream<T> flattenStreams<T>(Stream<Stream<T>> source) async* {
  await for (var stream in source) yield* stream;
}

后一种情况更为复杂,因为它需要一次收听多个流,并合并其事件。 (如果一次仅StreamController.addStream一次允许一个以上的流,那么会容易得多)。您可以为此使用StreamGroup中的package:async类:

import "package:async/async" show StreamGroup;

Stream<T> mergeStreams<T>(Stream<Stream<T>> source) {
  var sg = StreamGroup<T>();
  source.forEach(sg.add).whenComplete(sg.close);
  // This doesn't handle errors in [source].
  // Maybe insert 
  //   .catchError((e, s) {
  //      sg.add(Future<T>.error(e, s).asStream())
  // before `.whenComplete` if you worry about errors in [source].          
  return sg.stream;
}

答案 1 :(得分:0)

如果要Stream>返回Stream,则基本上需要平整流。 平面地图功能就是您在这里使用的功能

public static void main(String args[]) {
    StreamTest st = new StreamTest<String>();
    List<String> l = Arrays.asList("a","b", "c");
    Stream s = l.stream().map(i -> st.getStream(i)).flatMap(i->i);
}

Stream<T> static getStream(T uid) {
    // a sample code that returns a stream
    return Stream.of(uid);
}

如果需要第一个对象,请使用findFirst()方法

public static void main(String args[]) {
    StreamTest st = new StreamTest<String>();
    List<String> l = Arrays.asList("a","b", "c");
    String str = l.stream().map(i -> st.getStream(i)).flatMap(i->i).findFirst().get();
}

答案 2 :(得分:0)

在研究了将Stream<Stream<T>>展平为单个Stream<T>的几种方法之后,我发现有几种方法可以做到这一点。在这里,我将列出它们:

1。使用纯飞镖

@@ Irn回答,这是一种纯飞镖解决方案:

Stream<T> flattenStreams<T>(Stream<Stream<T>> source) async* {
  await for (var stream in source) yield* stream;
}

Stream<int> getStream(String v) {
    return Stream.fromIterable([1, 2, 3, 4]);
}

void main() {
    List<String> list = ["a", "b", "c"];
    Stream<int> s = flattenStreams(Stream.fromIterable(list).map(getStream));
    s.listen(print);
}

输出:1 2 3 4 1 2 3 4 1 2 3 4

2。使用Observable.flatMap

Observable具有flatMap方法,该方法可以平展输出流并将其附加到进行中的流:

import 'package:rxdart/rxdart.dart';

Stream<int> getStream(String v) {
    return Stream.fromIterable([1, 2, 3, 4]);
}

void main() {
    List<String> list = ["a", "b", "c"];
    Observable<int> s = Observable.fromIterable(list).flatMap(getStream);
    s.listen(print);
}

输出:1 2 3 4 1 2 3 4 1 2 3 4

3。使用Observable.switchLatest

  

将发出流的流(也称为“高阶流”)转换为单个Observable,该可观察项发出最近流发射的流。

这是我一直在寻找的解决方案!我只需要内部流发出的最新输出。

import 'package:rxdart/rxdart.dart';

Stream<int> getStream(String v) {
    return Stream.fromIterable([1, 2, 3, 4]);
}

void main() {
    List<String> list = ["a", "b", "c"];
    Observable<int> s = Observable.switchLatest(
            Observable.fromIterable(list).map(getStream));
    s.listen(print);
}

输出:1 1 1 2 3 4