點燈坊

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

使用 range() 建立連續值 Array

Sam Xiao's Avatar 2019-09-27

range() 也算實務上常用的 function,只要傳入 初始值結束值,就可建立 Array,在很多語言都有內建 range(),但可惜 ECMAScript 並沒有,但 Ramda 已經內建 range(),可直接使用。

Version

macOS Mojave 10.14.6
VS Code 1.38.1
Quokka 1.0.253
Ramda 0.26.1

Imperative

let range = start => end => {
  let size = end - start;
  return [...Array(size).keys()].map(i => i + start);
};

range(1)(4); // ?

使用 ECMAScript 建立也很簡單,首先 endstart 相減求出 size,以此 size 建立新的 array,再透過 keys() 回傳以 index 所建立的 array。

但我們要的是以 start 為開始,再透過 map() 產生一個新的 array 即可。

range000

Pipeline

import { pipe, keys, map, add } from 'ramda';

let getSize = start=> end => () => end - start;

let genArray = x => [...Array(x)];

let range = start => end => pipe(
  getSize(start)(end),
  genArray,
  keys,
  map(add(start)),
)();

range(1)(4); // ?

回想我們實作 range() 的思路:

  1. startend 獲得 size
  2. size 建立新的 array
  3. 以 array 的 index 再建立新的 array
  4. 將 array 的每個 item 加上 start

既然我們已經有了想法,就將每個步驟寫成 function,然後再以 pipe() 串起來,這就是 FP 了。

第 3 行

let getSize = start=> end => () => end - start;

建立 getSize(),由 startend 求得 size 回傳。

第 5 行

let genArray = x => [...Array(x)];

由 size 建立新的 array。

至於由 index 建立新的 array,Ramda 有提供 keys(),我們直接使用即可。

將 array 的每個 item 加上 start,也可直接使用 Ramda 的 map()

第 7 行

let range = start => end => pipe(
  getSize(start)(end),
  genArray,
  keys,
  map(add(start)),
)();

因此 range() 就是將 getSize()getArray()keys()map() 4 個 function 加以 pipeline 而成。

其中前兩個 function 為自己建立,keys()map() 則使用 Ramda 的 function。

range001

Function Composition

import { compose, keys, map, add } from 'ramda';

let getSize = start=> end => () => end - start;

let genArray = x => [...Array(x)];

let range = start => end => compose(
  map(add(start)),
  keys,
  genArray,
  getSize(start)(end),
)();

range(1)(4); // ?

既然能使用 pipe() 達成 pipeline,反向使用 compose() 就是 function composition 了。

range003

Ramda

import { range } from 'ramda';

range(1)(4); // ?

其實 Ramda 已經內建了 range(),可直接使用。

range()
Number → Number → [Number]
提供 element 的起始值與結束值建立新 array

Number:element 起始值

Number:element 結束值 (不包含)

[Number]:回傳新 array

range002

Conclusion

  • 若我們不知道 Ramda 已經提供 range(),也可自行以既有的 function 組合出 range()

Reference

Ramda, map()
Ramda, pipe()
Ramda, compose()
Ramda, keys()
Ramda, add()
Ramda, curry()
Ramda, range()