點燈坊

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

使用 pluck() 從 Object Functor 取出特定 Property

Sam Xiao's Avatar 2020-11-20

實務上常將 Array 中 Object 的某個 Property 取出其 Value 成為新 Array,且不希望有 Object 與 Key,此時可使用 pluck() 取代 map(prop())

Version

Ramda 0.27.1

Imperative

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

let f = (k, a) => {
  let result = []

  for (let x of a)
    result.push(x[k])

  return result
}

f('title', data) // ?

若我們只想取得 title property 資料並回傳新 Array,pluck() 只要傳入 titledata 即可。

Imperative 會使用 for loop 將 title property 取出塞入 result array 回傳。

pluck003

ECMAScript

reduce()

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

let f = (k, a) => a.reduce((ac, x) => [...ac, x[k]], [])

f('title', data) // ?

只要能使用 for loop,就能使用 reduce() 改寫。

pluck004

map()

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

let f = (k, a) => a.map(x => x[k])

f('title', data) // ?

熟悉 FP 的人直覺會用 map() 實現。

pluck005

Ramda

import { map } from 'ramda'

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

let f = k => map(x => x[k])

f('title')(data) // ?

也可使用 Ramda 的 map() 使 f() 能 point-free。

pluck000

Point-free

import { map, prop } from 'ramda'

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

let f = k => map(prop(k))

f('title')(data) // ?

也可使用 Ramda 的 prop() 使 map() 的 callback 也 point-free。

pluck002

Function Pipeline

import { pipe, map, prop } from 'ramda'

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

pipe(
  prop,
  map
)('title')(data) // ?

也可使用 pipe()prop()map() 組合起來,這樣連 k 也 point-free 了。

pluck006

pluck()

import { pluck } from 'ramda'

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

pluck('title', data) // ?

由於 pluck() 經常使用,且是 FP 代表性 function,因此 Ramda 已經內建可直接使用。

pluck()
Functor f => k → f {k: v} → f v
從 Functor 的特定 property 的 value 取出,成為新 Functor

k:object 的 key

f {k: v}:Functor 內為 object

f v:回傳 Functor 內為 value

pluck001

Conclusion

  • 當出現 map(prop(k))pipe(prop, map),別忘了使用 pluck() 重構

Reference

Ramda, map()
Ramda, prop()
Ramda, pluck()
Ramda, pipe()