點燈坊

失くすものさえない今が強くなるチャンスよ

使用 takeLastWhile() 根據自訂條件取得 String 最後幾個 Char

Sam Xiao's Avatar 2019-07-18

takeLast() 只能取得 String 固定最後幾個 Char,若想自行提供自訂條件 Predicate,就得使用 takeLastWhile()

Version

macOS Mojave 10.14.5
VS Code 1.36.1
Quokka 1.0.235
Ramda 0.26.1

Imperative

let data = 'FP in JavaScript';

// takeLastWhile :: (a → Boolean) → String → String
let takeLastWhile = pred => str => {
  let result = '';

  for(let i = str.length - 1; i >= 0; i--) {
    if (pred(str[i]))
      result = str[i] + result;
    else
      break;
  }

  return result;
};

takeLastWhile(x => x !== ' ')(data); // ?

takeLastWhile() 意義為當 predicate 為 true 時從最後取得 char,直到 false 時停止取得。

建立 takeLastWhile(),imperative 會先建立回傳 result string,i 從最後 index 開始,當 predicate 成立時,從 result 前面塞進 char,不成立馬上離開 for loop,最後回傳 result

takewhile003

Functional

import { pipe, reverse, takeWhile } from 'ramda';

let data = 'FP in JavaScript';

// takeLastWhile :: (a → Boolean) → String → String
let takeLastWhile = pred => pipe(
  reverse,
  takeWhile(pred),
  reverse
);

takeLastWhile(x => x !== ' ')(data); // ?

若一開始不知道 takeLastWhile() 也沒關係,可藉由已知的 takeWhile() 加以組合:

  • 使用 reverse() 將 string 反轉
  • 使用 takeWhile() 根據 predicate 條件取得 char
  • 使用 reverse() 再將 string 反轉

最後使用 pipe() 組合所有 function,非常清楚。

takewhile004

Point-free

import { pipe, reverse, takeWhile, useWith, identity } from 'ramda';

let data = 'FP in JavaScript';

// takeLastWhile :: (a → Boolean) → String → String
let takeLastWhile = useWith(
  pipe(takeWhile, reverse), [
    identity, 
    reverse
  ]
);

takeLastWhile(x => x !== ' ')(data); // ?

也可以使用 useWith() 進一步將 pred point-free,由 pipe() 寫法可發現:

  • reverse() 看似最後執行,但實則 pipe(takeWhile, reverse) 才是最後執行 function
  • 第一個 argument 為 predicate,因為不變,所以為 identity()
  • 第二個 argument 為 reverse()

由於第一個 argument 與第二個 argument 並不相關,明顯暗示需使用 useWith() 才能 point-free。

takewhile005

Ramda

import { takeLastWhile } from 'ramda';

let data = 'FP in JavaScript';

takeLastWhile(x => x !== ' ')(data); // ?

Ramda 已經提供 takeLastWhile(),可直接使用。

takeLastWhile()
(a → Boolean) → [a] → [a]
根據自訂條件取得 string 最後幾個 char

(a -> Boolean):自訂條件 predicate

[a]:data 為 string

[a]:回傳 string 最後幾個 char

takewhile001

Point-free

import { takeLastWhile, equals, complement } from 'ramda';

let data = 'FP in JavaScript';

let pred = complement(equals(' '));

takeLastWhile(pred)(data); // ?

也可將 x => x !== ' ' 進一步 point-free。

  • 使用 equals() 判斷相等,相當於 === ' '
  • 使用 complement() 使其結果反向,相當於 !

takewhile002

Conclusion

  • takeLastWhle()takeWhile() 用法很類似,但 takeWhile() 是取得前幾個 char,而 takeLastWhile() 是取得最後幾個 char
  • takeLastWhile() 除了用在 string,也能用在 array

Reference

Ramda, takeWhile()
Ramda, complement()
Ramda, equals()