點燈坊

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

使用 map() 將 Array 重新 mapping 成另一個 Array

Sam Xiao's Avatar 2020-01-27

map() 是 FP 最常用的 Higher Order Function,事實上我們也可自行實作 map() 練習 FP 基本功。

Version

macOS Catalina 10.15.2
VS Code 1.41.1
Quokka 1.0.274
Ramda 0.26.1

Imperative

let data = [1, 2, 3]

let map = fn => arr => {
  let result = []

  for(let x of arr)
    result.push(fn(x))

  return result
}

map(x => x * 2)(data) // ?

map() 當然也可使用 imperative 實作。

map000

reduce()

let data = [1, 2, 3]

let map = fn => arr => arr.reduce((a, x) => [...a, fn(x)], [])
  
map(x => x * 2)(data) // ?

map() 最終為單一 array,故可用 reduce() 與 ES6 的 array spread 實現。

map001

Recursion

let data = [1, 2, 3]

let map = fn => ([h, ...t]) => h === undefined ? [] : [fn(h), ...map(fn)(t)]

map(x => x * 2)(data) // ?

也可使用 resursion 以 no side effect 方式實現 map()

map006

map()

let data = [1, 2, 3]

let map = fn => arr => arr.map(fn)
  
map(x => x * 2)(data) // ?

Array.prototype 已經內建 map(),可直接使用。

map002

Ramda

import { map } from 'ramda'

let data = [1, 2, 3]

map(x => x * 2)(data) // ?

Ramda 亦提供 map(),與內建不同的是 data 放在最後一個 argument,方便 function composition。

map()
(a -> b) -> [a] -> [b]
將 array 重新 mapping 成另一個 array

(a -> b):傳入 map function 轉換

[a]:data 為 array

[b]:回傳另一個 array

map003

Point-free

import { map, multiply } from 'ramda'

let data = [1, 2, 3]

map(multiply(2))(data) // ?

map() 的 callback 亦可使用 multiply() 加以 point-free。

map004

Function Composition

import { map, multiply, compose } from 'ramda'

let data = [1, 2, 3]

let fn = compose(map, multiply)

fn(2)(data) // ?

亦可使用 compose()multiply()map() 組合起來。

map005

Conclusion

  • map() 雖然用起來很直覺,也可使用 imperative 與 reduce() 實作,事實上 imperative 要重構時,與自行實作 map() 思考過程類似
  • 當 map function 也 point-free 後,就更能看出 function composition 雛形,可使用 compose()map() 與 callback 組合起來

Reference

MDN, Array.prototype.reduce()
MDN, Array.prototype.map()
Ramda, map()
Ramda, multiply()