點燈坊

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

使用 zipAllWith() 將 n 個 Array 合併

Sam Xiao's Avatar 2020-02-13

zipWith() 只能將 2 個 Array 合併,若要將 n 個 Array 合併呢 ? Ramda 並沒有提供適當 Function,我們可自行組合出 zipAllWith()

Version

macOS Catalina 10.15.3
VS Code 1.41.1
Quokka 1.0.276
Ramda 0.26.1
Wink-fp 1.20.47

zipWith()

import { reduce, zipWith, add, head, tail } from 'ramda'

let data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

let _result = zipWith(add)([1, 2, 3])([4, 5, 6]) //?
let result = zipWith(add)(_result)([7, 8, 9]) // ?

若使用 zipWith(),我們只能先傳入 [1, 2, 3][4, 5, 6] 先合併,然後將結果 _result 在與 [7, 8, 9] 合併。

zipallwith000

reduce()

import { reduce, zipWith, add, head, tail } from 'ramda'

let data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

reduce(zipWith(add))(head(data))(tail(data)) // ?

由於 data 是 array,因此可透過 reduce() 循環執行,初始值以 head(data) 取得 [1, 2, 3],data 以 tail(data) 取得剩下的 [[4, 5, 6], [7, 8, 9]]

zipallwith001

zipAllWith()

import { reduce, zipWith, head, tail, add, converge } from 'ramda'

let data1 = [1, 2, 3]
let data2 = [4, 5, 6]
let data3 = [7, 8, 9]

let zipAllWith = f => converge(
  reduce(zipWith(f)), [head, tail]
)

zipAllWith(add)([data1, data2, data3]) // ?

是否能更一般化組合出 zipAllWith() 呢 ?

我們可發現 data 經過 head()tail() 處理後,最後再交給 reduce(zipWith()) 處理,這剛好是 converge() 的形式。

由於 zipWith() 重點在於傳入的 callback,zipAllWith() 也依然保有傳入 callback 的特性。

zipallwith002

Wink-fp

import { add } from 'ramda'
import { zipAllWith } from 'wink-fp'

let data1 = [1, 2, 3]
let data2 = [4, 5, 6]
let data3 = [7, 8, 9]

zipAllWith(add)([data1, data2, data3]) // ?

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

zipAllWith()
((a, a) -> b) -> [[a]...] -> [b]
自行提供 function 將 n 個 array 合併

zipallwith003

Conclusion

  • Ramda 所提供的 function 其 data 都是一個與兩個,若要 n 個,可使用本文方式透過 array 與 reduce() 加以擴充