#はじめに
pythonやKotlinでは連続する数の配列などを以下のように簡単に生成することができます。
//ラムダ式を用いた初期化
val x = Array(5, { it })
#rangeを用いた初期化
x = list(range(0,5))
同様に偶数からなる配列は以下のように生成できます。
val x = Array(5, { it * 2 })
#リスト内包表記
x = [x * 2 for x in range(0, 5)]
特にPythonのリスト内包表記を使うと短く書くことができます。今回はこのような配列の初期化をJavaScriptで試してみます。
#0で埋めた配列
Array(5).fill(0) //[0, 0, 0, 0, 0]
new Array(5).fill(0) //これも可
JavaScriptの配列生成では[]
を用いたリテラル表記が頻出ですが、コンストラクタを用いて生成することもできます。第一引数に配列の長さを指定します。
またJavaScriptの標準ビルトインオブジェクトの一部は、new演算子の省略が認められています。(ただし、new演算子を省略した場合に挙動が変わるものがあるので注意が必要です。)
#undefinedで埋めた配列
Array(5).fill() //[undefined, undefined, undefined, undefined, undefined]
0埋めの亜種ですが、fillメソッドの引数を省略することでundefinedで埋めることができます。この形がこれ以降に紹介する派生パターンの基本となります。
ちなみにfillメソッドは必要なの?と感じますが、必要です。
Array(5) // [ <5 empty items> ]
このように、undefinedで埋められているわけではないことがわかります。これについては、MDNから引用します。
これは arrayLength 分の空のスロットがある配列を意味します。スロットに実際の undefined 値があるわけではありません
#連番の配列
Array(5).fill().map((_, i) => i) //[0, 1, 2, 3, 4]
undefined埋めの配列にmapメソッドを適用します。mapメソッドに与える関数の第二引数には配列のインデックスが渡されますので、これを返してやることで連番を生成します。
#連続する偶数の配列
Array(5).fill().map((_, i) => i*2) //[0, 2, 4, 6, 8]
Array(5).fill().filter((_, i) => i*2).filter(v => v % 2 === 0) //[0, 2, 4]
Array(5).fill().map((_, i) => i).filter(v => v % 2 === 0) //上に同じ
mapメソッドやfilterメソッドを使うことで実現できます。mapのみで行う方法では配列の長さ(配列の長さが5)を指定、filterを用いる方法は範囲(配列の要素のとる値が0から5まで)を指定できます。
#二次元配列
Array(5).fill().map(() => Array(5).fill(0))
//[ [ 0, 0, 0, 0, 0 ],
// [ 0, 0, 0, 0, 0 ],
// [ 0, 0, 0, 0, 0 ],
// [ 0, 0, 0, 0, 0 ],
// [ 0, 0, 0, 0, 0 ] ]
0埋め配列の変形です。
以下はダメな例です。
Array(5).fill(Array(5).fill(0))
//[ [ 0, 0, 0, 0, 0 ],
// [ 0, 0, 0, 0, 0 ],
// [ 0, 0, 0, 0, 0 ],
// [ 0, 0, 0, 0, 0 ],
// [ 0, 0, 0, 0, 0 ] ]
このようにしてしまうと、内側の配列は全て同じ場所を参照する配列となってしまいます。つまり以下のように一箇所の値を変更すると他の部分まで変更されてしまいます。
const x = Array(5).fill(Array(5).fill(0))
x[0][1] = 1
console.log(x)
//[ [ 0, 1, 0, 0, 0 ],
// [ 0, 1, 0, 0, 0 ],
// [ 0, 1, 0, 0, 0 ],
// [ 0, 1, 0, 0, 0 ],
// [ 0, 1, 0, 0, 0 ] ]
#他の作り方
##Array.from()を用いる方法
Array.from(Array(5)) //[undefined, undefined, undefined, undefined, undefined]
Array.from(Array(5)).fill(0) //[0, 0, 0, 0, 0]
Array.from(Array(5), (_, i) => i) //[0, 1, 2, 3, 4]
##Array()の代わりにオブジェクトを利用する方法
Array.from({length:5}) //[undefined, undefined, undefined, undefined, undefined]
Array.from({length:5}).fill(0) //[0, 0, 0, 0, 0]
Array.from({length:5}, (_, i) => i) //[0, 1, 2, 3, 4]
lengthプロパティを持つオブジェクトは、配列風のオブジェクトとみなされるためArray.from()
で配列に変換可能です。
#連番の他の作り方
##Object.keys()と...を用いる方法
Array.from(Array(5).keys()) //[0, 1, 2, 3, 4]
[...Array(5).keys()] //[0, 1, 2, 3, 4]
配列のキーを取得するObject.keys()
を用います。Array(5).keys()
はIteratorを返すのみですのでfor...in文などには用いることができますが、配列としては使えません。Iteratorを配列に変換すのために、Array.from
またはスプレッド構文を用いています
#実用性は無い
##文字列から生成
Array.from("0".repeat(5)).map(i => parseInt(i))
ちなみに以下のようにすると二番目にNaNが出てきます。原因がわからないのですが、わかる方がいらっしゃればご教授いただきたいです
Array.from("0".repeat(5)).map(parseInt) //[ 0, NaN, 0, 0, 0 ] なぜ NaN ?
##ジェネレータで生成
Array.from((function*(){for(let i = 0; i < 5; i++) yield i})())
コードゴルフみたい。
#まとめ
個人的にはArray(5).fill().map(...)
が好きですが、Array.from(Array(5), ...)
もありかなという気がします。初投稿で拙い点が多々あったと思いますが、最後まで読んでいただきありがとうございました。٩( 'ω' )و