點燈坊

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

使用 zipWith 將兩個 Array 合併成自訂形式

Sam Xiao's Avatar 2021-06-22

zip 只能制式的將兩個 Array 合併成 Array Pair,若想將兩個 Array 合併成其他形式則要使用 zipWith

Version

Sanctuary 3.1.0

zip

import { zip } from 'sanctuary'

let girls = [
  { name: 'Mary' },
  { name: 'Jessie' }
]

let boys = [
  { name: 'John', car: 'BMW' },
  { name: 'Tomy', car: 'TOYOTA' },
  { name: 'Paul', car: 'Benz' }
]

let f = zip

f (girls) (boys) // ?

想將 girlsboys 兩個 Array 合併,直覺會使用 zip

zip 只能合併成制式的 Array Pair。

zipwith000

zipWith

import { zipWith } from 'sanctuary'

let girls = [
  { name: 'Mary' },
  { name: 'Jessie' }
]

let boys = [
  { name: 'John', car: 'BMW' },
  { name: 'Tomy', car: 'TOYOTA' },
  { name: 'Paul', car: 'Benz' }
]

let f = zipWith (x => y => `${x.name}: ${y.car}`)

f (girls) (boys) // ?

若想合併成 Array String,且格式為 name: car,其中 name 來自於 girls,而 car 來自於 boys

對於自訂形式合併,可使用 zipWith 提供自訂 function。

zipWith
(a -> b -> c) -> Array a -> Array b -> Array c
自行提供 function 的 zip

(a -> b → c):傳入 function 描述合併方式

Array a:data 為 Array

Array b:data 為 Array

Array c:回傳合併後新 Array

zip 相當於 zipWith (Pair)

zipwith001

Point-free

import { zipWith, prop } from 'sanctuary'
import { useWith } from 'ramda'
import { formatN } from 'wink-fp'

let girls = [
  { name: 'Mary' },
  { name: 'Jessie' }
]

let boys = [
  { name: 'John', car: 'BMW' },
  { name: 'Tomy', car: 'TOYOTA' },
  { name: 'Paul', car: 'Benz' }
]

let toString = useWith (
  formatN (2) ('{0}: {1}'), [prop ('name'), prop ('car')]
)

let f = zipWith (toString)

f (girls) (boys) // ?

若想進一步將傳入 zipWith 的 function 也 Point-free,可使用 useWith 加以組合:

  • formatN (2) ('{0}: {1}'):建立 template string
  • prop ('name'):從 girls 取出 name
  • prop ('car'):從 boys 取出 car

zipwith002

Conclusion

  • Ramda 的 zipWith 傳入 function 的 type signature 為 (a, b) -> c;而 Sanctuary 的 zipWith 傳入 function 的 type signature 為 a -> b -> c,僅管不相同,但都可使用 useWith 加以 Point-free

Reference

Sanctuary, zipWith