[RxJS] 數學/聚合類型 Operators (1) - min / max / count / reduce

|

今天要介紹「數學/聚合類型」的 operators,這些 operators 會把來源 Observable 當作一個單純的資料列,取得一些基本的資訊,也可以自訂如何判斷資訊;這些 operators 都非常直覺好懂,就讓我們輕鬆來學習吧!

min

min 會判斷來源 Observable 資料的最小值,在來源 Observable 結束後,將最小值事件資料發生在新的 Observable 上。

of(5, 1, 9, 8)
  .pipe(min())
  .subscribe(data => {
    console.log(`min 示範 (1): ${data}`);
  });
// min 示範 (1): 1

彈珠圖:

(   5   1   9   8|)
max()
(               1|)

min 內也可以傳入 comparer callback function,會傳入 xy 代表兩個來源 Observable 的事件資料, min 會透過 comparer function 的回傳值判斷兩組資料的大小,這個 callback function 需要回傳一個數值,大於 0 代表 x 大於 y,小於 0 代表 x 小於 y,等於 0 代表 xy 相同。

of(
  { name: 'Student A', score: 80 },
  { name: 'Student B', score: 90 },
  { name: 'Student C', score: 60 },
  { name: 'Student D', score: 70 },
).pipe(
  min((studentA, studentB) => studentA.score - studentB.score)
).subscribe(student => {
  console.log(`min 示範 (2): ${student.name} - ${student.score}`);
});
// min 示範 (2): Student C - 60

透過 comparer function,就不用擔心傳入資料為物件時無法比較囉。

程式碼:https://stackblitz.com/edit/mastering-rxjs-operator-min

max

max 剛好跟 min 相反,max 會判斷來源 Observable 資料的最大值,在來源 Observable 結束後,將最大值事件資料發生在新的 Observable 上。

of(5, 1, 9, 8)
  .pipe(max())
  .subscribe(data => {
    console.log(`max 示範 (1): ${data}`);
  });
// max 示範 (1): 9

彈珠圖:

(   5   1   9   8|)
max()
(               9|)

一樣的 max 也可以傳入 comparer callback function 來自定判斷資料大小比較條件:

of(
  { name: 'Student A', score: 80 },
  { name: 'Student B', score: 90 },
  { name: 'Student C', score: 60 },
  { name: 'Student D', score: 70 },
).pipe(
  max((studentA, studentB) => studentA.score - studentB.score)
).subscribe(student => {
  console.log(`max 示範 (2): ${student.name} - ${student.score}`);
});
// max 示範 (2): Student B - 90

程式碼:https://stackblitz.com/edit/mastering-rxjs-operator-max

count

count 可以用來計算來源 Observable 發生過多少次事件:

of(5, 1, 9, 8)
  .pipe(count())
  .subscribe(data => {
    console.log(`count 示範 (1): ${data}`);
  });
// count 示範 (1): 4

上述程式碼 of(5, 1, 9, 8) 總共會發生 4 次事件,因此在來源 Observable 結束時,新的 Observable 會得到資料 4 的事件值。

彈珠圖:

(   5   1   9   8|)
count()
(               4|)
                ^ 來源 Observable 發生過 4 次事件

count 可以傳入 predicate callback function,來判斷事件資料是否符合固定條件,當來源 Observable 結束時,新的 Observable 會發生的事件值為「所有符合指定條件事件」的總數:

of(5, 1, 9, 8)
  .pipe(count(data => data > 5))
  .subscribe(data => {
    console.log(`count 示範 (2): ${data}`);
  });
// count 示範 (2): 2

彈珠圖:

(   5   1   9   8|)
count(data => data > 5)
(               2|)
                ^ 來源 Observable 符合條件的事件發生過 2 次

程式碼:https://stackblitz.com/edit/mastering-rxjs-operator-count

reduce

reduce 用來運算來源 Observable 彙總後的結果,與之前介紹過的 scan 非常像,差別在於 scan 在來源 Observable 發生事件後都會進行運算並同時在新的 Observable 上發生,而 reduce 在來源 Observable 發生事件後,只會進行運算,但不會在新的 Observable 上發生事件,直到來源 Observable 結束時,才在新的 Observable 上發生運算後的結果作為事件。

回顧一下 scan

const donateAmount = [100, 500, 300, 250];

const accumDonate$ = of(...donateAmount).pipe(
  scan(
    (acc, value) => acc + value, // 累加函數
    0 // 初始值
  )
);

accumDonate$.subscribe(amount => {
  console.log(`目前 donate 金額累計:${amount}`)
});
// 目前 donate 金額累計:100
// 目前 donate 金額累計:600
// 目前 donate 金額累計:900
// 目前 donate 金額累計:1150

彈珠圖:

(100      500      300      250|)
scan((acc, value) => acc + value, 0)
(100      600      900     1150|)

同樣的程式碼,我們直接把 scan 換成 reduce

const donateAmount = [100, 500, 300, 250];

const accumDonate$ = of(...donateAmount).pipe(
  reduce(
    (acc, value) => acc + value, // 累加函數
    0 // 初始值
  )
);

accumDonate$.subscribe(amount => {
  console.log(`目前 donate 金額累計:${amount}`)
});
// 目前 donate 金額累計:1150

彈珠圖:

(100      500      300      250|)
reduce((acc, value) => acc + value, 0)
(                          1150|)

是不是一下就看出差異啦!

程式碼:https://stackblitz.com/edit/mastering-rxjs-operator-reduce

本日小結

  • min:找出來源 Observable 事件的最小值。
  • max:找出來源 Observable 事件的最大值。
  • count:找出來源 Observable 事件總數。
  • reduce:依照指定運算邏輯,找出來源 Observable 事件彙總的結果。

相關資源

如果您覺得我的文章有幫助,歡迎免費成為 LikeCoin 會員,幫我的文章拍手 5 次表示支持!