實務上有時需要在每一筆資料間新增顯示資料,如 Divider,Ramda 已經內建 intersperse()
,可直接使用。
Imperative
let data = [1, 2, 3]
let intersperse = separator => arr => {
let result = []
for(let i = 0; i < arr.length; i++) {
if (i === arr.length - 1)
result.push(arr[i])
else
result.push(arr[i], separator)
}
return result
}
intersperse(0)(data) // ?
若想在 [1, 2, 3]
之間加上 0
,成為 [1, 0, 2, 0, 3]
,imperative 會判斷只要不是最後一筆就會加上 0
,若最後一筆就不加。
Reduce()
let data = [1, 2, 3]
let intersperse = separator => arr => arr.reduce(
(a, x, i) => (i === arr.length - 1) ? [...a, x] : [...a, x, separator]
, [])
intersperse(0)(data) // ?
Imperative 也能使用 reduce()
加以改寫。
Functional
import { map, pipe, flatten, dropLast } from 'ramda'
let data = [1, 2, 3]
let intersperse = separator => pipe(
map(x => [x, separator]),
flatten,
dropLast(1)
)
intersperse(0)(data) // ?
若以 Functional 角度思考:
- 每一筆資料加上
0
之後,從一筆變兩筆 - 刪除最後一筆資料
第 6 行
map(x => [x, separator]),
使用 map()
將每一筆資料變成兩筆,回傳為 array。
12 行
flatten,
因為每一筆都是 array,所以變成了如下的兩層 array。
[ [ 1, 0 ], [ 2, 0 ], [ 3, 0 ] ]
這並不是我們要的,因此須使用 flatten()
加以攤平。
13 行
dropLast(1)
因為最後一筆 0
不是我們要的,所以使用 dropLast(1)
刪除之。
我們發現使用 FP 後,透過
pipe()
組合map()
、flatten()
與dropLast()
,整個演算法清楚可見,不必如 imperative 須 trace code 才知道演算法為何。
Point-free
import { map, pipe, flatten, dropLast, pair, __ } from 'ramda'
let data = [1, 2, 3]
let intersperse = separator => pipe(
map(pair(__, separator)),
flatten,
dropLast(1)
)
intersperse(0)(data) // ?
第 6 行
map(pair(__, separator)),
由於 map()
主要產生新的 array,可改由 pair()
higher order function 產生 mapper function。
chain()
import { chain, pipe, dropLast, pair, __ } from 'ramda'
let data = [1, 2, 3]
let intersperse = separator => pipe(
chain(pair(__, separator)),
dropLast(1)
)
intersperse(0)(data) // ?
map()
+ flatten()
組合在 ECMAScript 稱為 flatMap()
,在 Ramda 稱為 chain()
,可使用 chain()
加以取代。
Ramda
import { intersperse } from 'ramda'
let data = [1, 2, 3]
intersperse(0)(data) // ?
Ramda 已經內建 intersperse()
,可直接使用。
intersperse()
a → [a] → [a]
對 array 中每筆資料間新增一筆資料
a
:要新增的資料
[a]
:data 為 array
[a]
:新增資料後的 array
Conclusion
- Ramda 的 255 個 function 中,一開始可能不知道所有 function 功能,可先使用已知 function 組合,隨著經驗累積,就可使用功能更強 function