Rxjs is a library for doing reactive programming. Creation operators are useful for generating data from various data sources to be subscribed to by Observers.
In this article, we’ll look at some filtering operators, including the distinct
, distinctUntilChanged
, and distinctUntilKeyChanged
operators.
distinct
The distinct
operator emits the items from the source Observable that are distinct in comparison to previous items from the source.
It takes 2 optional arguments. The first is the keySelector
function, which lets us select which value we want to check as distinct.
The second is an optional flushes
Observable for flushing the internal HashSet from the operator.
It returns a new Observable that emits values that are distinct.
A simple example would be the following:
import { of } from "rxjs";
import { distinct } from "rxjs/operators";
of(3, 3, 3, 3, 3, 3, 35, 5, 7, 8, 4, 6, 3, 5, 2, 4, 2)
.pipe(distinct())
.subscribe(x => console.log(x));
We have the following Observable with duplicate values:
of(3, 3, 3, 3, 3, 3, 35, 5, 7, 8, 4, 6, 3, 5, 2, 4, 2)
The values from it is pipe
d to the distinct()
operator to filter out duplicate values.
Then we get:
3
35
5
7
8
4
6
2
from the console.log
.
We can also check if some key of an entry is distinct as follows:
import { of } from "rxjs";
import { distinct } from "rxjs/operators";
const people = [
{ age: 4, name: "Joe" },
{ age: 7, name: "Jane" },
{ age: 5, name: "Jane" }
];
of(...people)
.pipe(distinct(p => p.name))
.subscribe(x => console.log(x));
The code above spreads the people
array as the arguments of the of
operator, which emits the objects in the people
array. Then the emitted values are pipe
d into the distinct
operator, which selects the name
property to check for distinctness.
Then only the objects with a different name
value is emitted.
In the end, we get:
{age: 4, name: "Joe"}
{age: 7, name: "Jane"}
As the Observable.
distinctUntilChanged
distinctUntilChanged
emits all items emitted from the source Observable that are distinct by comparison from the previous item from the source.
It takes 2 optional arguments, which is a compare
function to test if an item is distinct from the previous item. The second argument is the keySelector
function to return the value of the key that we want to check.
A simple example would be as follows:
import { of } from "rxjs";
import { distinctUntilChanged } from "rxjs/operators";
of(1, 1, 5, 5, 6, 7, 8, 8, 8, 8, 9)
.pipe(distinctUntilChanged())
.subscribe(x => console.log(x));
The values from the of(1, 1, 5, 5, 6, 7, 8, 8, 8, 8, 9)
is pipe
d to the distinctUntilChanged
operator and the previously emitted value is checked against the currently emitted value to see if they’re the same.
Then we get:
1
5
6
7
8
9
since the value that’s different from the previously emitted one is emitted.
For Observables that emit objects, we can check if the property’s value is considered the same by passing in a function to the distinctUntilChanged
operator as follows:
import { of } from "rxjs";
import { distinctUntilChanged } from "rxjs/operators";
const people = [
{ age: 4, name: "Joe" },
{ age: 7, name: "Jane" },
{ age: 5, name: "Jane" }
];
of(...people)
.pipe(distinctUntilChanged((p, q) => p.name === q.name))
.subscribe(x => console.log(x));
The first and last parts work like the previous example. The difference is that now we have the (p, q) => p.name === q.name
function to check if the previously emitted name
value of the emitted object is the same as the currently emitted one.
Then we get:
{age: 4, name: "Joe"}
{age: 7, name: "Jane"}
as the output from console.log
.
distinctUntilKeyChanged
distinctUntilKeyChanged
returns an Observable that emits the value of a source Observable that’s distinct by the comparison with a key of the object emitted previously from the source.
This means that an item will be emitted if the value with the given key is different from the previously emitted object key’s value.
It takes up to 2 arguments. The first is the key
, which is a string with the object property to look up for each item.
The second is an optional compare
function, which is called to test if an item is distinct from the previously emitted item from the source Observable.
It returns an Observable that emits item from the source Observable with distinct property value from the previously emitted one from the source.
For example, we can rewrite the previous example:
import { of } from "rxjs";
import { distinctUntilChanged } from "rxjs/operators";
const people = [
{ age: 4, name: "Joe" },
{ age: 7, name: "Jane" },
{ age: 5, name: "Jane" }
];
of(...people)
.pipe(distinctUntilChanged((p, q) => p.name === q.name))
.subscribe(x => console.log(x));
into:
import { of } from "rxjs";
import { distinctUntilKeyChanged } from "rxjs/operators";
const people = [
{ age: 4, name: "Joe" },
{ age: 7, name: "Jane" },
{ age: 5, name: "Jane" }
];
of(...people)
.pipe(distinctUntilKeyChanged("name"))
.subscribe(x => console.log(x));
Then we should get the same result as before. All we did was changing:
distinctUntilChanged((p, q) => p.name === q.name)
to:
distinctUntilKeyChanged("name")
We can use the distinct
operator to get the distinct values emitted from a source Observable either by comparing primitive values or values of the properties of an object.
distinctUntilChanged
, and distinctUntilKeyChanged
let us emit the items from a source Observable that are different from the ones previously emitted by the source Observable. Again, it can compare by the primitive values or the values of the properties of an object.