iT邦幫忙

2022 iThome 鐵人賽

DAY 21
0
自我挑戰組

菜雞也能優雅的征服RxJS系列 第 21

菜雞們一起征服RxJS - day21: 蒐集不重複的資料 distinctUntilChanged及distinctUntilKeyChanged

  • 分享至 

  • xImage
  •  

  • 我們在處理資料的過程中,難免遇到重複且需要過濾掉的東西,distinctUntilChanged就是我們今天要介紹的好幫手,趕緊來看一看!☕

distinctUntilChanged


圖片來源-RxJS官網: distinctUntilChanged

函式解說:

  • 參數1:

default是undefined: 也就是說,可以不需要任何參數,系統會預設比對資料
(previous, current)=>boolean: 提供比對的函式,為true時則自動過濾掉

  • 參數2:

如果資料來源是一個object,可以提供key來擷取資料
雖然是一個不錯的方式,但RxJS提供一個更方便的方法,叫做distinctUntilKeyChanged

case1:distinctUntilChanged()

stackblitz

import { from, distinctUntilChanged } from 'rxjs';

const source$ = from([1, 1, 2, 3, 3, 3, 4, 3]);  // <-- 依序印出 1, 1, 2, 3, 3, 3, 4, 3
console.log('=== source ===');
source$.subscribe(console.log);

console.log('=== use distinctUntilChanged ===');
const dist$ = source$.pipe(distinctUntilChanged());  // <-- 自動比對每個數字,過濾掉重複的
dist$.subscribe(console.log);

// 印出
// 1
// 2
// 3
// 4
// 3
  • distinctUntilChanged()自動比對每個數字,一旦重複自動過濾掉,是不是很方便阿!
    stackblitz
...
const source$ = from([1, '1', 2, 3, 3, 3, 4, 3]); // <-- 依序印出 1, 1, 2, 3, 3, 3, 4, 3
//                       ^^^
//                     加入字串
...

previous: 1 , 格式number
current: '1', 格式string
兩者不同格式,自然比對為false,故不會被過濾掉囉!

case2: distinctUntilChanged(條件函式)

  • 下面的例子,我想要處理Object Array,並過濾掉重複的名字,先來看看不加入任何參數會發生什麼情形

stackblitz

import { from, distinctUntilChanged, map, distinctUntilKeyChanged } from 'rxjs';

const source$ = from([
  { name: 'One', age: 20 },
  { name: 'One', age: 30 },
  { name: 'One', age: 40 },
]);

console.log('=== use distinctUntilChanged ===');
const dist$ = source$.pipe(
  distinctUntilChanged()  //<-- 每個資料都印出來了
);
dist$.subscribe(console.log);

  • 由於Array裡每個Object都是獨一無二的記憶體位置,自然都為false,所以資料都會被輸出。
  • 因此,我們要解析key裡面的值,並做比對,此時,第一個參數就可以拿來設定我們的條件函示
...
const dist$ = source$.pipe(
  //distinctUntilChanged()  //<-- 每個資料都印出來了
  distinctUntilChanged((prev, current) => prev.name === current.name)//<--直接比對key的value
);
...

  • 現在來看,就能順利過濾啦!

case3: 改寫看看條件的比對

  • 我們設置條件式current>prev來觀察看看輸出的情形!

stackblitz

import { from, distinctUntilChanged, tap } from 'rxjs';

console.log('=== case2-1 use distinctUntilChanged with diff condition===');
const source$ = from([21, 22, 30, 21, 35, 18]);
const dist$ = source$.pipe(
  tap(console.log),
  distinctUntilChanged((prev, current) => {
    console.log(`check prev:${prev}, current:${current}:`, current > prev);
    return current > prev;
  })
);

dist$.subscribe({ next: (val) => console.log('===>', val) });

解析

  • 從輸出的結果來看,輸出為21, 21, 18!!??
  • 這裡你可能會有些混亂,不過別忘了distinctUntilChanged主要是 比對currentprev是否一致:

如果一致代表true,就將值剔除;如果false,將值輸出
如果一致代表true,就將值剔除;如果false,將值輸出
如果一致代表true,就將值剔除;如果false,將值輸出

  • 畫個流程圖,讓你更清楚流程:

同場加映: 比對key value有更好的方式 distinctUntilKeyChanged

  • 寫法1: 還記得第二個參數吧,如果你想直接針對key value進行比對,可以將第一個參數設定為undefined,設定第二個值讓他找到指定的key來做比對,不過...我認為這樣的寫法不夠直覺方便,因此我並不推薦這樣的方法

  • ✍ 使用distinctUntilKeyChanged(key)更直覺,比對一下兩個寫法,就知道哪個勝出啦!☕

...
const dist$ = source$.pipe(
  // distinctUntilChanged(undefined, (d) => d.name)  //<--寫法(1)
  distinctUntilKeyChanged('name') //<-- good to use!! //<-- 寫法(2)
);
...

✍Recap

  • distinctUntilChanged(): 過濾重複的值,給出不一樣的值。
  • distinctUntilChanged((previous, current)=>boolean):比對currentprevious的值是否一樣:

true一樣則剔除
false不一樣則輸出 <-- 注意是false喔!!

  • distinctUntilKeyChanged: 取key value來比對

  • 21天再度輕鬆搞定,還剩9天,目標清楚,繼續邁進!Go~~~


上一篇
菜雞也能優雅的征服RxJS - day20: 一旦符合條件就結束 takeUntil
下一篇
菜雞們一起征服RxJS - day22 - 別急~先讓子彈飛一會兒: debounceTime
系列文
菜雞也能優雅的征服RxJS32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言