點燈坊

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

如何替 Object Array 加上 Index ?

Sam Xiao's Avatar 2020-11-21

實務上常使用 Object Array,有時候必須在原本 Object 加上 Index,這種常見需求該如何實現呢 ?

Version

Ramda 0.27.1

mapIndex()

import { addIndex, map, pipe, pluck } from 'ramda'

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

let mapi = addIndex(map)

pipe(
  pluck('title'),
  mapi((x, i) => ({ key: i, title: x }))
)(data) // ?

第 3 行

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

data 原為只有 title 的 Object Array,想要變成帶有 key 的 Object Array。

第 9 行

let mapi = addIndex(map)

Ramda map() 的 callback 並沒有帶 index,必須使用 addIndex() 組合 map()

11 行

pipe(
  pluck('title'),
  mapi((x, i) => ({ key: i, title: x }))
)(data) // ?
  • 使用 pluck() 取出 title
  • 使用 mapi() 回傳帶有 key 的 Object Array

mapi001

zipObj()

import { addIndex, map, pipe, pluck, pair, zipObj, flip } from 'ramda'

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

let mapi = addIndex(map)

pipe(
  pluck('title'),
  mapi(flip(pair)),
  map(zipObj(['key', 'title']))
)(data) // ?

11 行

pipe(
  pluck('title'),
  mapi(flip(pair)),
  map(zipObj(['key', 'title']))
)(data) // ?

若不追求 point-free,其實 mapi() 配合 arrow function 就能達成需求。

若要使 mapi() 也能 point-free,由於最終結果為 keytitle 的 Object 只有兩個 property,可先使用 mapi() 轉成 Pair Array。

由於最終還是 Object Array,因此 map() 可使用 zipObj() 將兩個 array 合併成 Object。

mapi002

Wink-fp

import { addIndex, map, pipe, pluck, pair, zipObj, flip } from 'ramda'
import { mapi } from 'wink-fp'

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

pipe(
  pluck('title'),
  mapi(flip(pair)),
  map(zipObj(['key', 'title']))
)(data) // ?

mapi() 因為實務上經常使用,Wink-fp 已經提供 mapi()

mapi000

Conclusion

  • 若只要求結果正確,其實感受不到 Ramda 威力,在追求 point-free 下很多 arrow function 都能藉由 function 組合產生,這正是 Ramda 神奇之處

Reference

Ramda, addIndex()
Ramda, pair()
Ramda, zipObject()