Search code examples
dartstreamrxdart

RxDart, mapping each item of a list to another object coming from a never ending stream


I've been trying to find a nice way of doing this but I had no luck.

Here is a simplified version of the problem:

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");
  });
}

When running this, nothing is printed. This is because the subject never completes and thus the toList() never finishes building the list.

Replacing the subject with for example an Observable.just(index + 2) does work because the Observable completes and the toList() is able to collect them.

But the intended behavior is that the example should emit the new list of strings each time the subject is changed.

Any help would be appreciated,

Thanks!


Solution

  • You probably want to use combineLatest instead

    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]);
    }