點燈坊

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

使用 lookup() 取代 if else

Sam Xiao's Avatar 2021-03-22

使用 map() 時若需對值做簡單轉換,直覺會在 Arrow Function 內使用 if else 對應,事實上可以使用 lookup() 以 Point-free 實現。

Version

Wink-fp 1.26.0

if else

import { map } from 'ramda'

let data = [100, 200, 300, 400]

map(x => {
  if (x === 100) return 60
  else if (x === 200) return 70
  else if (x === 300) return 80
  else return 100
})(data) // ?

100 則轉成 60200 則轉成 70300 則轉成 80,其餘則轉成 100,直覺會在 map() 內使用 if else 轉換。

lookup000

Object

import { map } from 'ramda'

let data = [100, 200, 300, 400]

map(x => {
  let lookupTable = {
    100: 60,
    200: 70,
    300: 80
  }

  let result = lookupTable[x]
  return !result ? 50 : result
})(data) // ?

40 行

let lookupTable = {
  100: 60,
  200: 70,
  300: 80
}

let result = lookupTable[x]
return !result ? 50 : result

使用 Object 作為 lookup table 為 JavaScript 常用技巧,別忘了查詢不到時會回傳 undefined,藉由 falsy value 判斷回傳 default value。

lookup001

lookup()

import { map, propOr, curry } from 'ramda'

let data = [100, 200, 300, 400]

let lookup = curry((a, o, k) => propOr(a, k , o))

map(lookup(50, {
  100: 60,
  200: 70,
  300: 80
}))(data) // ?

使用 lookup table 雖然能取代 if else,但若能使 map() 能 Point-free 不使用 arrow function 就更完美了。

第 5 行

let lookup = curry((a, o, k) => propOr(a, k , o))

lookup table 本質是 Object,Ramda 的 propOr() 剛好適合,只是其 signature 不方便使用,特別建立 lookup() 調整 signature。

第 7 行

map(lookup(50, {
  100: 60,
  200: 70,
  300: 80
}))(data) // ?

lookup() 第一個 argument 提供 default value,第二個 argument 提供 lookup table。

lookup002

Wink-fp

import { map } from 'ramda'
import { lookup } from 'wink-fp'

let data = [100, 200, 300, 400]

map(lookup(50, {
  100: 60,
  200: 70,
  300: 80
}))(data) // ?

Wink-fp 已經提供 lookup() 可直接使用。

lookup()
a -> Object -> String -> a
提供 default value 與 lookup table 取代 if else

lookup003

Conclusion

  • lookup() 本質是 Ramda 的 propOr(),只是將其 signature 順序加以調整方便使用

Reference

Ramda, propOr()