點燈坊

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

使用 propIncludes() 判斷 Property 是否包含指定 String

Sam Xiao's Avatar 2020-08-30

若要判斷 Property 是否包含指定 String,Ramda 並沒有提供類似 propEq() 那樣直接的 Function,但我們可自行組合出 propIncludes()

Version

macOS Catalina 10.15.6
Wink-fp 1.23.2

Imperative

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

// f :: String -> [a] -> [a]
let f = s => a => {
  let result = []

  for(let x of a)
    if (x.title.includes(s))
      result.push(x)

  return result
}

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

Imperative 會使用 for loop,藉由 String.prototype.includes() 判斷指定是否存在,若存在則加入 result array 回傳。

propincludes000

String.prototype.includes()

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

// f :: String -> [a] -> [a]
let f = s => a => a.filter(x => x.title.includes(s))

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

第 7 行

// f :: String -> [a] -> [a]
let f = s => a => a.filter(x => x.title.includes(s))

也可使用 ECMAScript 的 filter() 搭配 includes() 求得。

propincludes001

propSatisfies()

import { propSatisfies, includes, filter } from 'ramda'

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

// f :: String -> [a] -> [a]
let f = s => filter(propSatisfies(includes(s), 'title'))

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

第 9 行

// f :: String -> [a] -> [a]
let f = s => filter(propSatisfies(includes(s), 'title'))

Ramda 亦提供 filter()includes(),但若要使 filter() 能 point-free,則必須搭配 propSatisfies(),整體可讀性較差。

propincludes002

propIncludes()

import { includes, filter, curry, useWith, prop, pipe, chain, ap, flip } from 'ramda'

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

// propIncludes :: (k, v) -> {k: v} -> Boolean
let propIncludes = (k, v) => o => includes(v, prop(k, o))

// f :: String -> [a] -> [a]
let f = s => filter(propIncludes('title', s))

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

12 行

// f :: String -> [a] -> [a]
let f = s => filter(propIncludes('title', s))

若能提供類似 propEq()propIncludes(),則可讀性更高。

第 9 行

// propIncludes :: (k, v) -> {k: v} -> Boolean
let propIncludes = (k, v) => o => includes(v, prop(k, o))

使用用 prop() 取得 value,再使用 includes() 判斷。

propincludes006

Point-free

import { includes, filter, curry, useWith, prop, pipe } from 'ramda'

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

// propIncludes :: k -> v -> {k: v} -> Boolean
let propIncludes = useWith(
  pipe, [prop, includes]
)

// f :: String -> [a] -> [a]
let f = s => filter(propIncludes('title', s))

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

第 9 行

// propIncludes :: k -> v -> {k: v} -> Boolean
let propIncludes = useWith(
  pipe, [prop, includes]
)

亦可使用 useWith() 使其 point-free。

propincludes003

Wink-fp

import { propSatisfies, includes, filter } from 'ramda'
import { propIncludes } from 'wink-fp'

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

// f :: String -> [a] -> [a]
let f = s => filter(propIncludes('title', s))

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

Wink-fp 已經內建 propIncludes() 可直接使用。

propIncludes()
k -> v -> {k: v} -> Boolean
判斷指定 String 是否在 Object 的 Property 內

k:指定 property 的 key

v:指定 String

{k: v}:data 為 Object

Boolean:回傳 Boolean 結果

propincludes004

Function Pipeline

import { propSatisfies, includes, filter, pipe } from 'ramda'
import { propIncludes } from 'wink-fp'

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

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

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

第 10 行

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

可使用 pipe() 串起 filter()propIncludes() 使 f() 能 point-free。

propincludes005

Conclusion

  • 對於 Object 的 predicate,Ramda 只提供了 propEq(),但因為 FP 很靈活,因此我們可以自行組合如 propGt()propGte() … 等類似 function 方便產生 predicate

Reference

Ramda, propSatisfies()