Concat observables reusing the previous results












0















Imagine I have 3 functions, taking some arguments and returning an observable. Logic would be (all would be a result of something async):




  1. Get a cat.

  2. Pet the cat.

  3. Get food for the cat based on it's mood after petting it.


Sample code:



function getCat(): Observable<Cat> {
return Observable.of({ name: 'Larry' })
}

function petCat(cat: Cat): Observable<Mood> {
return Observable.of(Mood.HAPPY)
}

function getFood(cat: Cat, mood: Mood): Observable<Food> {
return Observable.of({ type: 'fish' })
}




  1. I would like to end up with an Observable that's equivalent with this:



    Observable.from([{ name: 'Larry' }, Mood.HAPPY, { type: 'fish' }])



  2. I would like the functions to be invoked in sequence (obviously from the parameter signatures)


  3. I would not like to delay the individual emits, in the final observable I'd like to get the results as soon as they arrive.


I could get it working with something like this:



function perform() {
return getCat().pipe(
mergeMap((cat) => concat(
of(cat),
petCat(cat).pipe(
mergeMap((mood) => concat(
of(mood),
getFood(cat, mood)
))
)
)
),
)
}


Question is, is there a better, more readable way of doing this (let's say I would have 5 of these that I would like to chain)?










share|improve this question





























    0















    Imagine I have 3 functions, taking some arguments and returning an observable. Logic would be (all would be a result of something async):




    1. Get a cat.

    2. Pet the cat.

    3. Get food for the cat based on it's mood after petting it.


    Sample code:



    function getCat(): Observable<Cat> {
    return Observable.of({ name: 'Larry' })
    }

    function petCat(cat: Cat): Observable<Mood> {
    return Observable.of(Mood.HAPPY)
    }

    function getFood(cat: Cat, mood: Mood): Observable<Food> {
    return Observable.of({ type: 'fish' })
    }




    1. I would like to end up with an Observable that's equivalent with this:



      Observable.from([{ name: 'Larry' }, Mood.HAPPY, { type: 'fish' }])



    2. I would like the functions to be invoked in sequence (obviously from the parameter signatures)


    3. I would not like to delay the individual emits, in the final observable I'd like to get the results as soon as they arrive.


    I could get it working with something like this:



    function perform() {
    return getCat().pipe(
    mergeMap((cat) => concat(
    of(cat),
    petCat(cat).pipe(
    mergeMap((mood) => concat(
    of(mood),
    getFood(cat, mood)
    ))
    )
    )
    ),
    )
    }


    Question is, is there a better, more readable way of doing this (let's say I would have 5 of these that I would like to chain)?










    share|improve this question



























      0












      0








      0








      Imagine I have 3 functions, taking some arguments and returning an observable. Logic would be (all would be a result of something async):




      1. Get a cat.

      2. Pet the cat.

      3. Get food for the cat based on it's mood after petting it.


      Sample code:



      function getCat(): Observable<Cat> {
      return Observable.of({ name: 'Larry' })
      }

      function petCat(cat: Cat): Observable<Mood> {
      return Observable.of(Mood.HAPPY)
      }

      function getFood(cat: Cat, mood: Mood): Observable<Food> {
      return Observable.of({ type: 'fish' })
      }




      1. I would like to end up with an Observable that's equivalent with this:



        Observable.from([{ name: 'Larry' }, Mood.HAPPY, { type: 'fish' }])



      2. I would like the functions to be invoked in sequence (obviously from the parameter signatures)


      3. I would not like to delay the individual emits, in the final observable I'd like to get the results as soon as they arrive.


      I could get it working with something like this:



      function perform() {
      return getCat().pipe(
      mergeMap((cat) => concat(
      of(cat),
      petCat(cat).pipe(
      mergeMap((mood) => concat(
      of(mood),
      getFood(cat, mood)
      ))
      )
      )
      ),
      )
      }


      Question is, is there a better, more readable way of doing this (let's say I would have 5 of these that I would like to chain)?










      share|improve this question
















      Imagine I have 3 functions, taking some arguments and returning an observable. Logic would be (all would be a result of something async):




      1. Get a cat.

      2. Pet the cat.

      3. Get food for the cat based on it's mood after petting it.


      Sample code:



      function getCat(): Observable<Cat> {
      return Observable.of({ name: 'Larry' })
      }

      function petCat(cat: Cat): Observable<Mood> {
      return Observable.of(Mood.HAPPY)
      }

      function getFood(cat: Cat, mood: Mood): Observable<Food> {
      return Observable.of({ type: 'fish' })
      }




      1. I would like to end up with an Observable that's equivalent with this:



        Observable.from([{ name: 'Larry' }, Mood.HAPPY, { type: 'fish' }])



      2. I would like the functions to be invoked in sequence (obviously from the parameter signatures)


      3. I would not like to delay the individual emits, in the final observable I'd like to get the results as soon as they arrive.


      I could get it working with something like this:



      function perform() {
      return getCat().pipe(
      mergeMap((cat) => concat(
      of(cat),
      petCat(cat).pipe(
      mergeMap((mood) => concat(
      of(mood),
      getFood(cat, mood)
      ))
      )
      )
      ),
      )
      }


      Question is, is there a better, more readable way of doing this (let's say I would have 5 of these that I would like to chain)?







      javascript typescript rxjs observable






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 14 '18 at 17:50







      Balázs Édes

















      asked Nov 14 '18 at 17:29









      Balázs ÉdesBalázs Édes

      9,31723258




      9,31723258
























          1 Answer
          1






          active

          oldest

          votes


















          1














          You can try something like



          getCat()
          .pipe(
          switchMap(cat => petCat(cat).pipe(map(mood => ({cat, mood})))),
          switchMap(({cat, mood}) => getFood(cat, mood))
          )


          The whole idea is to use switchMap to switch from the source Observable to the Observable returned by the function passed to switchMap as parameter.



          Maybe worth of mentioning is the use of map chained into the pipe of the first switchMap. That map operator makes sure that we keep cat as part of the parameters we pass the second, and last, switchMap.



          UPDATE after comment
          If the function perform has to emit all the 3 elements emitted by the 3 functions, then you may try something like the following



          function perform() {
          return getCat()
          .pipe(
          switchMap(cat => petCat(cat).pipe(map(mood => ({cat, mood})))),
          switchMap(({cat, mood}) => getFood(cat, mood).pipe(map(food => ({cat, mood, food}))))
          )
          }





          share|improve this answer


























          • Hey @Picci, thanks for the answer. The problem with this answer, is that it will only emit the last value in the returned observable.

            – Balázs Édes
            Nov 15 '18 at 9:50











          • What would you expect to get as result? The simulating functions you propose just emit 1 element. In the real case do you expect any of the Observables actually emit more than 1 value?

            – Picci
            Nov 15 '18 at 12:18











          • I mean the final perform() function. It emits all 3 elements from the 3 functions in a single observable.

            – Balázs Édes
            Nov 19 '18 at 10:32











          • @Balázs Édes I have updated my answer

            – Picci
            Nov 19 '18 at 21:48











          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%2f53305760%2fconcat-observables-reusing-the-previous-results%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          You can try something like



          getCat()
          .pipe(
          switchMap(cat => petCat(cat).pipe(map(mood => ({cat, mood})))),
          switchMap(({cat, mood}) => getFood(cat, mood))
          )


          The whole idea is to use switchMap to switch from the source Observable to the Observable returned by the function passed to switchMap as parameter.



          Maybe worth of mentioning is the use of map chained into the pipe of the first switchMap. That map operator makes sure that we keep cat as part of the parameters we pass the second, and last, switchMap.



          UPDATE after comment
          If the function perform has to emit all the 3 elements emitted by the 3 functions, then you may try something like the following



          function perform() {
          return getCat()
          .pipe(
          switchMap(cat => petCat(cat).pipe(map(mood => ({cat, mood})))),
          switchMap(({cat, mood}) => getFood(cat, mood).pipe(map(food => ({cat, mood, food}))))
          )
          }





          share|improve this answer


























          • Hey @Picci, thanks for the answer. The problem with this answer, is that it will only emit the last value in the returned observable.

            – Balázs Édes
            Nov 15 '18 at 9:50











          • What would you expect to get as result? The simulating functions you propose just emit 1 element. In the real case do you expect any of the Observables actually emit more than 1 value?

            – Picci
            Nov 15 '18 at 12:18











          • I mean the final perform() function. It emits all 3 elements from the 3 functions in a single observable.

            – Balázs Édes
            Nov 19 '18 at 10:32











          • @Balázs Édes I have updated my answer

            – Picci
            Nov 19 '18 at 21:48
















          1














          You can try something like



          getCat()
          .pipe(
          switchMap(cat => petCat(cat).pipe(map(mood => ({cat, mood})))),
          switchMap(({cat, mood}) => getFood(cat, mood))
          )


          The whole idea is to use switchMap to switch from the source Observable to the Observable returned by the function passed to switchMap as parameter.



          Maybe worth of mentioning is the use of map chained into the pipe of the first switchMap. That map operator makes sure that we keep cat as part of the parameters we pass the second, and last, switchMap.



          UPDATE after comment
          If the function perform has to emit all the 3 elements emitted by the 3 functions, then you may try something like the following



          function perform() {
          return getCat()
          .pipe(
          switchMap(cat => petCat(cat).pipe(map(mood => ({cat, mood})))),
          switchMap(({cat, mood}) => getFood(cat, mood).pipe(map(food => ({cat, mood, food}))))
          )
          }





          share|improve this answer


























          • Hey @Picci, thanks for the answer. The problem with this answer, is that it will only emit the last value in the returned observable.

            – Balázs Édes
            Nov 15 '18 at 9:50











          • What would you expect to get as result? The simulating functions you propose just emit 1 element. In the real case do you expect any of the Observables actually emit more than 1 value?

            – Picci
            Nov 15 '18 at 12:18











          • I mean the final perform() function. It emits all 3 elements from the 3 functions in a single observable.

            – Balázs Édes
            Nov 19 '18 at 10:32











          • @Balázs Édes I have updated my answer

            – Picci
            Nov 19 '18 at 21:48














          1












          1








          1







          You can try something like



          getCat()
          .pipe(
          switchMap(cat => petCat(cat).pipe(map(mood => ({cat, mood})))),
          switchMap(({cat, mood}) => getFood(cat, mood))
          )


          The whole idea is to use switchMap to switch from the source Observable to the Observable returned by the function passed to switchMap as parameter.



          Maybe worth of mentioning is the use of map chained into the pipe of the first switchMap. That map operator makes sure that we keep cat as part of the parameters we pass the second, and last, switchMap.



          UPDATE after comment
          If the function perform has to emit all the 3 elements emitted by the 3 functions, then you may try something like the following



          function perform() {
          return getCat()
          .pipe(
          switchMap(cat => petCat(cat).pipe(map(mood => ({cat, mood})))),
          switchMap(({cat, mood}) => getFood(cat, mood).pipe(map(food => ({cat, mood, food}))))
          )
          }





          share|improve this answer















          You can try something like



          getCat()
          .pipe(
          switchMap(cat => petCat(cat).pipe(map(mood => ({cat, mood})))),
          switchMap(({cat, mood}) => getFood(cat, mood))
          )


          The whole idea is to use switchMap to switch from the source Observable to the Observable returned by the function passed to switchMap as parameter.



          Maybe worth of mentioning is the use of map chained into the pipe of the first switchMap. That map operator makes sure that we keep cat as part of the parameters we pass the second, and last, switchMap.



          UPDATE after comment
          If the function perform has to emit all the 3 elements emitted by the 3 functions, then you may try something like the following



          function perform() {
          return getCat()
          .pipe(
          switchMap(cat => petCat(cat).pipe(map(mood => ({cat, mood})))),
          switchMap(({cat, mood}) => getFood(cat, mood).pipe(map(food => ({cat, mood, food}))))
          )
          }






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 19 '18 at 21:47

























          answered Nov 14 '18 at 18:00









          PicciPicci

          5,37252749




          5,37252749













          • Hey @Picci, thanks for the answer. The problem with this answer, is that it will only emit the last value in the returned observable.

            – Balázs Édes
            Nov 15 '18 at 9:50











          • What would you expect to get as result? The simulating functions you propose just emit 1 element. In the real case do you expect any of the Observables actually emit more than 1 value?

            – Picci
            Nov 15 '18 at 12:18











          • I mean the final perform() function. It emits all 3 elements from the 3 functions in a single observable.

            – Balázs Édes
            Nov 19 '18 at 10:32











          • @Balázs Édes I have updated my answer

            – Picci
            Nov 19 '18 at 21:48



















          • Hey @Picci, thanks for the answer. The problem with this answer, is that it will only emit the last value in the returned observable.

            – Balázs Édes
            Nov 15 '18 at 9:50











          • What would you expect to get as result? The simulating functions you propose just emit 1 element. In the real case do you expect any of the Observables actually emit more than 1 value?

            – Picci
            Nov 15 '18 at 12:18











          • I mean the final perform() function. It emits all 3 elements from the 3 functions in a single observable.

            – Balázs Édes
            Nov 19 '18 at 10:32











          • @Balázs Édes I have updated my answer

            – Picci
            Nov 19 '18 at 21:48

















          Hey @Picci, thanks for the answer. The problem with this answer, is that it will only emit the last value in the returned observable.

          – Balázs Édes
          Nov 15 '18 at 9:50





          Hey @Picci, thanks for the answer. The problem with this answer, is that it will only emit the last value in the returned observable.

          – Balázs Édes
          Nov 15 '18 at 9:50













          What would you expect to get as result? The simulating functions you propose just emit 1 element. In the real case do you expect any of the Observables actually emit more than 1 value?

          – Picci
          Nov 15 '18 at 12:18





          What would you expect to get as result? The simulating functions you propose just emit 1 element. In the real case do you expect any of the Observables actually emit more than 1 value?

          – Picci
          Nov 15 '18 at 12:18













          I mean the final perform() function. It emits all 3 elements from the 3 functions in a single observable.

          – Balázs Édes
          Nov 19 '18 at 10:32





          I mean the final perform() function. It emits all 3 elements from the 3 functions in a single observable.

          – Balázs Édes
          Nov 19 '18 at 10:32













          @Balázs Édes I have updated my answer

          – Picci
          Nov 19 '18 at 21:48





          @Balázs Édes I have updated my answer

          – Picci
          Nov 19 '18 at 21:48




















          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%2f53305760%2fconcat-observables-reusing-the-previous-results%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

          Xamarin.iOS Cant Deploy on Iphone

          Glorious Revolution

          Dulmage-Mendelsohn matrix decomposition in Python