This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

Filtering operators: distinct and distinctUntilChanged

4:34 RxJS lesson by

Operator distinct() and its variants are an important type of Filtering operator. This lessons shows how they work and in what cases are they useful.

Get the Code Now
click to level up comment guidelines


Operator distinct() and its variants are an important type of Filtering operator. This lessons shows how they work and in what cases are they useful.


For people using TypeScript, you have have to import 'rxjs/add/operator/distinct'; Distinct was not included when importing 'rxjs/Rx'; and my build was erroring out.

var result = foo.distinct((x,y) => x.toLowerCase() === y.toLowerCase());

gives: "error: TypeError: y is undefined"

Should be:

var result = foo.distinct((x) => x.toLowerCase());

Hi Mike. That's correct. We should update the lesson to use a 'keySelector' function, not a 'compare' function.

In reply to Mike

More on filtering operators, let's take a look now at distinct. As the name hints distinct allows only unique values on the output observable. So suppose you have this input observable over here, and if we draw the marble diagram for distinct it looks like this. Once it sees a it will keep a in the registry, and then it will emit a. Then when it sees b, it will check if b is in the registry. Because it's not, the registry has an array of only a, then it will emit b, and now the registry has a and b.

So then when it sees a again, it check that a is already in the registry, and that's why it will skip a. Then when it sees c, c is not in the registry, it will put c in the registry and it will emit c. B was already in the registry, it skips it, and then it's complete. That was distinct. If we run this, we will see a, b, and c only. But let's suppose you have this case here, uppercase A. Because uppercase A is actually distinct to lower case a, it would emit this uppercase A.

In those cases distinct allows you to give a custom compare function as an argument in order to tell what does equality mean. In this case we would like to say uppercase A is actually the same as lowercase a. We do that by specifying what does equality mean for us, and here we can give a function with two arguments, and we can check if their lowercase versions are the same. If we run this we should see that this uppercase A was skipped it already happened in the past according to our equality definition, like that.

Also distinct, besides taking this argument, you ca also give a flusher argument. This here is an observable, and this observable dictates when should the registry be cleared. Let's write that flusher observable. If we draw this flusher observable in a marble diagram it looks like this, and it doesn't complete. So once this 0 happen, it will clear the registry and that's why it will emit a, and also c it will emit that, and b did not happen since this time, so that's why it will also this lowercase b, like that.

However, distinct is not that often used as you may think it is. Actually most of the cases people want instead this DistinctUntilChanged, which is a variant of distinct. DistinctUntilChanged does not keep a registry of everything from the past, but it keeps a registry of just the most recent events from the past. Let's take a look how it is in a marble diagram with the lowercase a here. Once it sees lowercase a it is distinct to what happened in the past which is nothing, that's why emitted.

B is distinct to a, that why emits b, a is distinct to b, emits a, also c is, and b is. Let's say you would have instead of c here, you would have a, and in this case because a is the same as what just happened, it would skip this lowercase a. That is DistinctUntilChanged. If we run this, we will see just a, b, a, b. In a nutshell distinct and DistinctUntilChanged as rate limiting operators, let's say you would have many As here happening fast or really frequently.

DistinctUntilChanged would just ignore all of these, and emit like that. Or it can be used also has just a filtering function in order to avoid redundant events, that's also the biggest use case for DistinctUntilChanged.

Joel's Head
Why are we asking?