要件
- 関数名は
range
とする - 数値型の引数を2つ(
start
,end
)受け取る -
start
から始まりend
で終わる整数値の連番を配列で返す
const list = range(2, 5);
console.log(list);
[2,3,4,5]
実装
forで回す
const range = (start, end) => {
const list = [];
for (let i = start; i <= end; i++ ) {
list.push(i);
}
return list;
}
Array.fromを使う
MDNのサンプルコードを参考に
const range = (start, stop) => Array.from({ length: (stop - start) + 1}, (_, i) => start + i);
スプレッド構文を使う
- 一番短く書けて、実行も早かった
const range = (start, end) => [...Array(end + 1).keys()].slice(start);
やっていること
-
Array(end + 1)
=> end + 1の長さの配列を作成。MDN:Arrayコンストラクタ -
.key()
=> 作った配列のindexを返すArray Iteratorを作成。MDN:Array.prototype.keys()
-
[...Array(end + 1).keys()]
=> スプレッド構文でiteratorを配列に変換する。MDN:スプレッド構文 -
.slice(start)
=> 0からの連番になっているので、sliceを使ってstart番目から始まる配列のコピーを作成。MDN:Array.prototype.slice()
一言
keys()
がphpのarray_keysと同じで配列返すと思っていたのでArray(end + 1).keys().slice(start)
でもいけるのでは?と思った。
戻り値イテレータだった。slice
は配列なのに・・・
スプレッド構文を使う(改良版)
コメントにてパフォーマンス面で無駄があること指摘していただいたので改良しました。
ひとつ前のsliceでカットする方法だと、startが大きくなった時に無駄に配列を確保することになるので直しました。
const range = (start, end) => [...Array((end - start) + 1)].map((_, i) => start + i);
おまけ(計測)
実行環境
Google Chrome
バージョン: 75.0.3770.142(Official Build) (64 ビット)
計測結果
※実行する環境によって実行速度やパフォーマンスの優劣は異なります。
自身の環境でお試しください。
方法 | 実行時間 | 平均(30回) |
---|---|---|
forで回す | 338~430ms(初回呼び出し) | 37ms |
20~30ms(2回目以降) | - | |
Array.fromを使う | 173~260ms | 192ms |
スプレッド構文+slice | 61~105ms | 121ms |
スプレッド構文+map | 35~60ms | 44ms |
See the Pen rangeいろいろ by r-kojima (@RyutaKojima) on CodePen.
一言
Chromeではforで回す方法が、初回は時間がかかるけど2回目以降の呼び出しがすごく早かった。
最適化がかかるのか、検証コードが間違っているのか、理由はよくわかりませんでした。