One of the confusing aspects about working with streams is diving into
Rx operators that take a stream and fan out into multiple streams.
Is your head exploding yet?
Let’s dive into a problem I ran into while working on a personal
The task at hand is to take a list of GPS moving point data and
partition the group data into multiple clusters of points, count up each
group, then return the aggregate stats. As a cyclist is moving, I want
to know how often they are moving at that specific velocity (speed).
Our weapon of choice is the RxJS groupBy() function,
which groups like stream values based on a key value you define.
OK. Easy enough. So my implementation looked something like this:
(point) => point.velocity function determines the
value for the supplied event, which then 1) creates a new Observable
sequence for that specific
key value, if it doesn’t exist, or 2)
assigns your event to an existing Observable sequence.
flatMap() to the rescue.
So the story turns to our hero
flatMap(), which as it turns out is
specifically tuned to deal with issues of dealing with multiple streams.
flatMap will take a supplied function as its argument, which is the
operation to apply to each argument within the supplied stream.
1 2 3 4 5 6
1 2 3
What just happened here?
I specified a merging function for the
flatMap() stream, which
scan() counting aggregation on my group before merging the
stream back into the main stream. I threw in a
zip, which annotated my
aggregate count value with a record of the group key (velocity) that
this value was computed for.
Compare it to imperative
The equivalent of
flatMap in imperative programming is, quite
_.flatMap(). With a few key
differences. Here it is in lodash:
1 2 3 4 5 6 7 8 9 10 11 12
So in the end, the end result was the same with one crucial difference -
our Observable, reactive version was able to take intermediate accounts
into time and perform an intermediate calculation as data was flowing
in. This allowed us to generate an intermediate count for the “0” velocity
- When you want to fan out a stream into groups or partitions based on a
specific stream value, turn to
- When you have a need to combine a stream-of-streams, you want to look at
flatMap. You may also consider looking at
concatMap, a close cousin of
- Reactive programming gives you more expressive abilities to reason
about time and event ordering. You just have to tilt your head a little
Updated typo where the
index variable on a GroupedObservable was
changed to correctly be