Combine Values of One Observable with RxJS scan

InstructorAndré Staltz

Published 8 years ago
Updated 3 years ago

All of the combination operators take two or more observables as input. These operators may also be alternatively called "vertical combination operators", because of how they work in a marble diagram. Next, we will learn about scan(), which is an important "horizontal combination operator".

🚨 Since we are importing `interval` from RxJS, we don't need to preface our Observables with `Rx.Observable`. You can no longer `.{operator}`, you need to `.pipe({operator})` instead. To link together multiple Observables and Operators, the method is a bit different. You call `zip` first, then list your Observables, your functions, then pipe your Operators.

[00:00] All of these combination operators take two or more observables as inputs. As we saw is usually the case where we have two or more observables, such as foo and bar, we're going to combine them in order to produce an output observable.

[00:13] I also call these operators as vertical combination operators. The reason why is when you look at the marble diagram, we're really combining in the vertical direction here, where we get a value from foo and bar, and then we produce a value on the output observable.

[00:26] We could also combine horizontally, and what does that mean? Let's say we want to take the value H and combine it with E, and then combine it with L.

[00:35] All of this, as you can see in the marble diagram, it's in the horizontal direction. It's only concerning one single observable, so we're not actually combining observables, multiple of them. We're just combining the values that happen over time on one observable.

[00:52] Let's look at one of these operators, and one of that is called scan. Scan, just like these, it also takes an argument which is a function, and that function takes two arguments. It takes accumulator and the current value.

[01:07] It's going to be clear soon what an accumulator means, but essentially, it is everything that happened previously combined with the current. So if you look at L here, L will be combined with everything that happened before, and that's basically the accumulator.

[01:23] Let's say here that in case the accumulator was HE, let's imagine that accumulator was HE, and we get the current value L, which is X, and we can just concatenate them together like this to produce HEL. Also, scan takes a second argument, which is called seed. I'm going to give it here on the empty string as seed.

[01:48] What that means is that this is the initial accumulator, so once we see the value H, then accumulator will be the empty string, the seed. Then X will be H, so I just concatenate the empty string with H, and I get H.

[02:08] The next accumulator will be H, so then when we see E, the accumulator will be H and the X will be E. Then H concatenated with E will give us HE

[02:21] So let's see that in action. The accumulator now is empty string, so empty string with H will gives us H. Then the accumulator is now H, and we can combine H with E to give us HE.

[02:37] Now the accumulator is HE, and HE concatenated with L gives us HEL. Then another L will give us HELL with two Ls, and then here, O with the accumulator HELL will give us HELLO, like that. It will immediately complete after that because it sees this completion.

[03:01] Let's see it used in action. This observable here is our observable that says HELLO over time. We can call scan on it, giving the accumulator and X will simply concatenate together, and the seed is the empty string. Then when we run this, we see H, HE, HEL, HELL, HELLO, and done, and that's how you combine events horizontally.

[03:30] Scan is really useful. Basically with merge, which is a pure vertical combinator, and scan, you have both directions. You have vertical and horizontal, and you can do a lot with those two.

[03:44] Scan is really useful because, in a sense, it accumulates state. The accumulator is a state. It basically is a memory here. Basically, when we see E, there is state stored inside the scan operator, which is the accumulator, and then this is how things work over time.

[04:04] One of the useful applications for scan is, let's say when you have an observable here, I'm just going to draw it. These are click events happening on some button. Then you can map each of these click events to the number one, and then you get here, one, one, and one.

[04:29] Then, if you use scan, here now let's give the seed as zero. It means that once it sees one, it will add zero plus one to give us one here. Then once it sees one here, it will add that to the accumulator, which was one, and we will get two. Now the accumulator is two, and once it sees one again, it's going to add two plus one to give us three.

[04:55] Basically, if this first observable here was an observable of clicks, now this is the number of times that that button was clicked. There you can see how scan accumulates a state, and is really useful in these cases.

[05:14] Scan is a horizontal combination operator, which means that the values that it's combining are coming from just one observable.

Steve Lee
~ 8 years ago

Rather than (hel) - 3 separate characters - shouldn't the result be 'hel' - a string. I was thinking acc+x will be string catenation given the seed is a the empty string. Am I missing something?

André Staltzinstructor
~ 8 years ago

Hi Steve. We took some freedom to write it more concisely. The precisely correct way of writing it would be ('hel'), but it would take too much space in the diagram.

Markdown supported.
Become a member to join the discussionEnroll Today