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












0















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!










share|improve this question























  • toList() won't execute when the stream is never ending. Perhaps all you need is https://api.dartlang.org/stable/2.1.0/dart-async/Stream/map.html with stream.map(...).listen(...)`

    – Günter Zöchbauer
    Nov 26 '18 at 9:55











  • I'd say combineLatest instead

    – Rémi Rousselet
    Nov 26 '18 at 9:59
















0















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!










share|improve this question























  • toList() won't execute when the stream is never ending. Perhaps all you need is https://api.dartlang.org/stable/2.1.0/dart-async/Stream/map.html with stream.map(...).listen(...)`

    – Günter Zöchbauer
    Nov 26 '18 at 9:55











  • I'd say combineLatest instead

    – Rémi Rousselet
    Nov 26 '18 at 9:59














0












0








0








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!










share|improve this question














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!







dart stream rxdart






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 26 '18 at 9:44









NorbertNorbert

5327




5327













  • toList() won't execute when the stream is never ending. Perhaps all you need is https://api.dartlang.org/stable/2.1.0/dart-async/Stream/map.html with stream.map(...).listen(...)`

    – Günter Zöchbauer
    Nov 26 '18 at 9:55











  • I'd say combineLatest instead

    – Rémi Rousselet
    Nov 26 '18 at 9:59



















  • toList() won't execute when the stream is never ending. Perhaps all you need is https://api.dartlang.org/stable/2.1.0/dart-async/Stream/map.html with stream.map(...).listen(...)`

    – Günter Zöchbauer
    Nov 26 '18 at 9:55











  • I'd say combineLatest instead

    – Rémi Rousselet
    Nov 26 '18 at 9:59

















toList() won't execute when the stream is never ending. Perhaps all you need is https://api.dartlang.org/stable/2.1.0/dart-async/Stream/map.html with stream.map(...).listen(...)`

– Günter Zöchbauer
Nov 26 '18 at 9:55





toList() won't execute when the stream is never ending. Perhaps all you need is https://api.dartlang.org/stable/2.1.0/dart-async/Stream/map.html with stream.map(...).listen(...)`

– Günter Zöchbauer
Nov 26 '18 at 9:55













I'd say combineLatest instead

– Rémi Rousselet
Nov 26 '18 at 9:59





I'd say combineLatest instead

– Rémi Rousselet
Nov 26 '18 at 9:59












2 Answers
2






active

oldest

votes


















1














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





share|improve this answer
























  • This works great for this example! Unfortunately, in the app I'm working on I have a Stream<User> getUser(String id) instead of one single observable containing all the users and therefore combineLatest doesn't working (because there can only be a maximum of 9 streams).

    – Norbert
    Nov 26 '18 at 10:37













  • I don't quite get your issue tbh

    – Rémi Rousselet
    Nov 26 '18 at 10:43



















0














Edit: shortly after posting this I realized that it completely depends on how the data is exposed:



If you have a method which has a signature like Observable<String> getStringForInt(int number) and you have to call it for every item in the list, my solution is the one for you. Note if the above method always subscribes to the same stream, changing that stream will result in multiple emissions (because combineLatest updates every item).



However, if you have access to the whole data container (like a Map


Original Answer



Ok, it turns out, it wasn't quite possible to achieve that with the implementation of rxDart.



The combineLatest constructor only supported up to 9 streams.



But since then, combineLatest with n-streams has been implemented and the solution to this problem would look something like this:



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


This will print:



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]





share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53478354%2frxdart-mapping-each-item-of-a-list-to-another-object-coming-from-a-never-ending%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














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





    share|improve this answer
























    • This works great for this example! Unfortunately, in the app I'm working on I have a Stream<User> getUser(String id) instead of one single observable containing all the users and therefore combineLatest doesn't working (because there can only be a maximum of 9 streams).

      – Norbert
      Nov 26 '18 at 10:37













    • I don't quite get your issue tbh

      – Rémi Rousselet
      Nov 26 '18 at 10:43
















    1














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





    share|improve this answer
























    • This works great for this example! Unfortunately, in the app I'm working on I have a Stream<User> getUser(String id) instead of one single observable containing all the users and therefore combineLatest doesn't working (because there can only be a maximum of 9 streams).

      – Norbert
      Nov 26 '18 at 10:37













    • I don't quite get your issue tbh

      – Rémi Rousselet
      Nov 26 '18 at 10:43














    1












    1








    1







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





    share|improve this answer













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






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 26 '18 at 10:00









    Rémi RousseletRémi Rousselet

    29.3k36592




    29.3k36592













    • This works great for this example! Unfortunately, in the app I'm working on I have a Stream<User> getUser(String id) instead of one single observable containing all the users and therefore combineLatest doesn't working (because there can only be a maximum of 9 streams).

      – Norbert
      Nov 26 '18 at 10:37













    • I don't quite get your issue tbh

      – Rémi Rousselet
      Nov 26 '18 at 10:43



















    • This works great for this example! Unfortunately, in the app I'm working on I have a Stream<User> getUser(String id) instead of one single observable containing all the users and therefore combineLatest doesn't working (because there can only be a maximum of 9 streams).

      – Norbert
      Nov 26 '18 at 10:37













    • I don't quite get your issue tbh

      – Rémi Rousselet
      Nov 26 '18 at 10:43

















    This works great for this example! Unfortunately, in the app I'm working on I have a Stream<User> getUser(String id) instead of one single observable containing all the users and therefore combineLatest doesn't working (because there can only be a maximum of 9 streams).

    – Norbert
    Nov 26 '18 at 10:37







    This works great for this example! Unfortunately, in the app I'm working on I have a Stream<User> getUser(String id) instead of one single observable containing all the users and therefore combineLatest doesn't working (because there can only be a maximum of 9 streams).

    – Norbert
    Nov 26 '18 at 10:37















    I don't quite get your issue tbh

    – Rémi Rousselet
    Nov 26 '18 at 10:43





    I don't quite get your issue tbh

    – Rémi Rousselet
    Nov 26 '18 at 10:43













    0














    Edit: shortly after posting this I realized that it completely depends on how the data is exposed:



    If you have a method which has a signature like Observable<String> getStringForInt(int number) and you have to call it for every item in the list, my solution is the one for you. Note if the above method always subscribes to the same stream, changing that stream will result in multiple emissions (because combineLatest updates every item).



    However, if you have access to the whole data container (like a Map


    Original Answer



    Ok, it turns out, it wasn't quite possible to achieve that with the implementation of rxDart.



    The combineLatest constructor only supported up to 9 streams.



    But since then, combineLatest with n-streams has been implemented and the solution to this problem would look something like this:



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


    This will print:



    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]





    share|improve this answer






























      0














      Edit: shortly after posting this I realized that it completely depends on how the data is exposed:



      If you have a method which has a signature like Observable<String> getStringForInt(int number) and you have to call it for every item in the list, my solution is the one for you. Note if the above method always subscribes to the same stream, changing that stream will result in multiple emissions (because combineLatest updates every item).



      However, if you have access to the whole data container (like a Map


      Original Answer



      Ok, it turns out, it wasn't quite possible to achieve that with the implementation of rxDart.



      The combineLatest constructor only supported up to 9 streams.



      But since then, combineLatest with n-streams has been implemented and the solution to this problem would look something like this:



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


      This will print:



      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]





      share|improve this answer




























        0












        0








        0







        Edit: shortly after posting this I realized that it completely depends on how the data is exposed:



        If you have a method which has a signature like Observable<String> getStringForInt(int number) and you have to call it for every item in the list, my solution is the one for you. Note if the above method always subscribes to the same stream, changing that stream will result in multiple emissions (because combineLatest updates every item).



        However, if you have access to the whole data container (like a Map


        Original Answer



        Ok, it turns out, it wasn't quite possible to achieve that with the implementation of rxDart.



        The combineLatest constructor only supported up to 9 streams.



        But since then, combineLatest with n-streams has been implemented and the solution to this problem would look something like this:



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


        This will print:



        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]





        share|improve this answer















        Edit: shortly after posting this I realized that it completely depends on how the data is exposed:



        If you have a method which has a signature like Observable<String> getStringForInt(int number) and you have to call it for every item in the list, my solution is the one for you. Note if the above method always subscribes to the same stream, changing that stream will result in multiple emissions (because combineLatest updates every item).



        However, if you have access to the whole data container (like a Map


        Original Answer



        Ok, it turns out, it wasn't quite possible to achieve that with the implementation of rxDart.



        The combineLatest constructor only supported up to 9 streams.



        But since then, combineLatest with n-streams has been implemented and the solution to this problem would look something like this:



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


        This will print:



        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]






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Dec 14 '18 at 12:29

























        answered Dec 14 '18 at 12:05









        NorbertNorbert

        5327




        5327






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53478354%2frxdart-mapping-each-item-of-a-list-to-another-object-coming-from-a-never-ending%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Contact image not getting when fetch all contact list from iPhone by CNContact

            count number of partitions of a set with n elements into k subsets

            A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks