若要找出兩個 Array 中共有的 Element 且不重複,Ramda 提供了 intersection()
。
Version
macOS Catalina 10.15.4
VS Code 1.43.2
Quokka 1.0.284
Ramda 0.27.0
Imperative
let data0 = [1, 3, 5, 3]
let data1 = [5, 7, 3, 7]
let intersection = fst => snd => {
let result = []
for(let x of fst) {
for(let y of snd) {
if (x === y) {
if (!result.includes(x))
result.push(x)
}
}
}
return result
}
intersection(data0)(data1) // ?
Imperative 會先建立 result
array,使用兩層 array 對 fst
與 snd
做 for
loop,若 x
與 y
相等且不在 result
內,則新增至 result
,最後回傳 result
array。
Functional
import { uniq, filter, flip, includes } from 'ramda'
let data0 = [1, 3, 5, 3]
let data1 = [5, 7, 3, 7]
let intersection = fst => snd => uniq(filter(flip(includes)(snd))(fst))
intersection(data0)(data1) // ?
Functional 思考方式如下:
- 以
fst
array 為主體,兩個 array 共用部分必為fst
array 的一部分,故使用filter()
filter()
的 callback 原本是x => snd.includes(x)
,可改用 Ramda 的includes()
產生,但includes()
的 signature 為a -> [a] -> Boolean
,故需flip(includes)
為[a] -> a -> Boolean
,才能由flip(includes)(snd)
產生a -> Boolean
的 callback- 最後使用
uniq()
將filter()
結果使之不重複
Point-free
import { uniq, filter, flip, includes } from 'ramda'
import { compose, useWith, identity } from 'ramda'
let data0 = [1, 3, 5, 3]
let data1 = [5, 7, 3, 7]
let intersection = flip(compose(
uniq,
useWith(filter, [flip(includes), identity])
))
intersection(data0)(data1) // ?
看到 uniq(filter(flip(includes)))
這麼多層,很明顯能使用 function composition 使之 point-free。
uniq()
與filter()
關係為簡單compose()
沒問題- 內層
flip(includes)
會先吸收一個 argument,外層filter()
會再吸收另一個 argument,這是很典型的useWith()
應用 - 由於
flip(includes)
接收的是snd
不是fst
,最後再使用flip()
顛倒
Ramda
import { intersection } from 'ramda'
let data0 = [1, 3, 5, 3]
let data1 = [5, 7, 3, 7]
intersection(data0)(data1) // ?
Ramda 已經提供 intersection()
可直接使用。
intersection()
[*] → [*] → [*]
找出兩個 array 中共有且不重複 element
[*]
:data 為第一個 array
[*]
:data 為第二個 array
[*]
:回傳兩 array 共有且不重複 element 的新 array
Object
import { intersection } from 'ramda'
let data0 = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 },
]
let data1 = [
{ title: 'FP in JavaScript', price: 400 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 500 },
]
intersection(data0)(data1) // ?
intersection()
除了能用在 primitive 外,也能用在 object。
Conclusion
- 若不知道
intersection()
,也可由includes()
、filter()
與uniq()
組合出來,唯中間必須靠flip()
、useWith()
等作微調
Reference
Ramda, intersection()
Ramda, uniq()
Ramda, filter()
Ramda, flip()
Ramda, includes()
Ramda, useWith()
Ramda, compose()
Ramda, identity()