【小ネタ】JavaScriptでJavaのIntStream.rangeみたいなことをやってみる

JavaScript

ネタのきっかけ

プログラミング学習というか、パズルを解いているときの問題で

「引数の数値 n を受け取り、0 ~ nまでの値にそれぞれ10を掛けた結果の合計を求めよ」

というような問題が出てきました。(問題の内容は変えてます。もうちょいやることあった気がする)

何も考えなければ、for文で書けるんだけど、JavaのIntStream.range(0, 10)のようにして、要素番号だけ取る方法はないのかな?と思ったのがきっかけです。

解決策

次のコードで解決しました。

const rangeArray = [...Array(10).keys()];

コード解説

基本的にはMDNをご覧いただければ、なんですが、簡単に解説。

Array()

Array() コンストラクター - JavaScript | MDN
Array() コンストラクターは Array オブジェクトを生成します。

この記事ではArray(arrayLength)を使っているため、arrayLength分の要素を持つ配列が生成されます。arrayLength渡すつもりで、数値以外のものを渡すと要素1つの配列が出来上がりますので注意してください。

Array.keys()

Array.prototype.keys() - JavaScript | MDN
keys() は Array インスタンスのメソッドで、配列内の各インデックスのキーを含む、新しい配列イテレーターオブジェクトを返します。

配列内の各インデックスのキーを含む新しいArrayイテレーターオブジェクトを返します。この記事のサンプルコードの場合は、0~9のイテレーターオブジェクトが返ります。

…(スプレッド構文)

スプレッド構文 - JavaScript | MDN
スプレッド構文 (...) を使うと、配列式や文字列などの反復可能オブジェクトを、0 個以上の引数 (関数呼び出しの場合) や要素 (配列リテラルの場合) を期待された場所で展開したり、オブジェクト式を、0 個以上のキーと値の組 (オブジェクトリテラルの場合) を期待された場所で展開したりすることができます。

配列などの反復可能オブジェクトを展開できます。解決策のコードは以下のような形となります。

[...Array(10).keys()]
-> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

サンプルコード

上記のような一部分だけだと、実装イメージがつかないと思われるので、簡単なサンプルコードも書いておこうと思います。

変数を使ったサンプルコード

上述のコードにある「Array(10)」の数値は、事前に変数定義したものでも(当然)動作します。従って、以下のようなコードで動作させることができます。

function main() {
  func(100);
}

function func(n) {
  // 0 ~ 99の要素番号が取れる。
  const rangeArray = [...Array(n).keys()];
  rangeArray.forEach(r => console.log(r));
}

やりたかったことに対する解決策のコード

function calc(n) {
  return [...Array(n).keys()]
            .map(i => i * 10)
            .reduce((acc, val) => acc + val);
}

0~9までの数値に順番に10を掛けて、reduceを使って合計値を算出しました。

for文で考えたもの

function calc(n) {
  let sum = 0;
  for (let i = 0; i < n; i++) {
    sum += i * 10;
  }
  return sum;
}

特に一行処理をさせたいとかなければ、オーソドックスなパターンじゃないかなと思います。

最後に

記事に起こしましたけど、このロジックが欲しいと思ったきっかけは最初に記載したとおり、プログラミングのパズルのようなものを解いている時だったので、実際にはあまり使わないかなぁと思いました。

と思ってたらこんな記事を見つけました。

[...Array(n).keys()] はやめた方がいいのでは?

記事にある通り、確かに読み手のコストは高いですかね…
JavaScript苦手マンな私は、最初何やっているか一層わからなかったし。
keysは未だによくわからんです。

コメント

タイトルとURLをコピーしました