點燈坊

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

使用 propNEq() 判斷 Property 是否不等於某值

Sam Xiao's Avatar 2020-09-01

Ramda 提供了 propEq(),專門產生比較 Property 是否 相等 的 Predicate,若 不等 呢 ? 理論上可以自己組合出新 Function,Wink-fp 已經提供 propNEq() 可直接使用。

Version

macOS Catalina 10.15.3
Wink-fp 1.23.2

filter()

import { filter } from 'ramda'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

// f :: a -> [Object] -> [Object]
let f = v => filter(x => x.title !== v)

f('Speaking JavaScript')(data) // ?

第 9 行

// f :: a -> [Object] -> [Object]
let f = v => filter(x => x.title !== v)

我們想找出所有 title 不是 Speaking JavaScript 的書,若使用 filter(),勢必使用 反向邏輯,也就是 !==

propneq000

not()

import { pipe, filter, propEq, not } from 'ramda'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

// f :: a -> [Object] -> [Object]
let f = v => filter(pipe(propEq('title', v), not))

f('Speaking JavaScript')(data) // ?

第 9 行

// f :: a -> [Object] -> [Object]
let f = v => filter(pipe(propEq('title', v), not))

使用 pipe()propEq()not() 組合起來,使 filter() 的 predicate 能 point-free。

propneq001

complement()

import { filter, propEq, complement } from 'ramda'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

// f :: a -> [Object] -> [Object]
let f = v => filter(complement(propEq)('title', v))

f('Speaking JavaScript')(data) // ?

第 9 行

// f :: a -> [Object] -> [Object]
let f = v => filter(complement(propEq)('title', v))

也可使用 propEq()complement(),這也能使 filter() 的 predicate 能 point-free。

propneq002

propNEq()

import { filter, propEq, complement } from 'ramda';

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

// propNEq :: String -> a -> Object -> Boolean
let propNEq = complement(propEq)

// f :: a -> [Object] -> [Object]
let f = v => filter(propNEq('title', v))

f('Speaking JavaScript')(data) // ?

第 9 行

// propNEq :: String -> a -> Object -> Boolean
let propNEq = complement(propEq)

若要模仿 propEq() 而有 propNEq(),可使用 complement()propEq() 組合。

12 行

// f :: a -> [Object] -> [Object]
let f = v => filter(propNEq('title', v))

如此在 filter() 內能簡單地使用 propNEq()

propneq005

Wink-fp

import { filter } from 'ramda'
import { propNEq } from 'wink-fp'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

// f :: a -> [Object] -> [Object]
let f = v => filter(propNEq('title', v))

f('Speaking JavaScript')(data) // ?

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

propNEq()
String -> a -> Object -> Boolean
判斷指定 Object 的 property 是否不等於該值

String:提供 Object 的 property

a:提供任意要比較的值

Object:data 為 Object

Boolean:若不相等則傳回 true,否則回傳 false

propneq004

Function Pipeline

import { pipe, filter } from 'ramda'
import { propNEq } from 'wink-fp'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

// f :: a -> [Object] -> [Object]
let f = pipe(
  propNEq('title'),
  filter
)

f('Speaking JavaScript')(data) // ?

10 行

// f :: a -> [Object] -> [Object]
let f = pipe(
  propNEq('title'),
  filter
)

有了 propNEq() 之後就可輕易組合 filter()propNEq(),使 f() 也能 point-free。

propneq006

Conclusion

  • 寫程式盡量避免 反向邏輯,應優先使用 正向邏輯 的 function,若不得已要使用 反向邏輯,則 Wink-fp 的 propNEq() 讓我們不必每次都自行組合 propEq()complement()

Reference

Ramda, filter()
Ramda, propEq()
Ramda, not()
Ramda, pipe()
Ramda, complement()