33
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JavaScriptの配列初期化

Posted at

#はじめに
pythonやKotlinでは連続する数の配列などを以下のように簡単に生成することができます。

Numbers.kt
//ラムダ式を用いた初期化
val x = Array(5, { it })
Numbers.py
#rangeを用いた初期化
x = list(range(0,5))

同様に偶数からなる配列は以下のように生成できます。

EvenNumbers.kt
val x = Array(5, { it * 2 })
Numbers.py
#リスト内包表記
x = [x * 2 for x in range(0, 5)]

特にPythonのリスト内包表記を使うと短く書くことができます。今回はこのような配列の初期化をJavaScriptで試してみます。

#0で埋めた配列

JavaScript
Array(5).fill(0) //[0, 0, 0, 0, 0]
new Array(5).fill(0) //これも可

JavaScriptの配列生成では[]を用いたリテラル表記が頻出ですが、コンストラクタを用いて生成することもできます。第一引数に配列の長さを指定します。
またJavaScriptの標準ビルトインオブジェクトの一部は、new演算子の省略が認められています。(ただし、new演算子を省略した場合に挙動が変わるものがあるので注意が必要です。)

#undefinedで埋めた配列

JavaScript
Array(5).fill() //[undefined, undefined, undefined, undefined, undefined]

0埋めの亜種ですが、fillメソッドの引数を省略することでundefinedで埋めることができます。この形がこれ以降に紹介する派生パターンの基本となります。

ちなみにfillメソッドは必要なの?と感じますが、必要です。

JavaScript
 Array(5) // [ <5 empty items> ]

このように、undefinedで埋められているわけではないことがわかります。これについては、MDNから引用します。

これは arrayLength 分の空のスロットがある配列を意味します。スロットに実際の undefined 値があるわけではありません

#連番の配列

JavaScript
Array(5).fill().map((_, i) => i) //[0, 1, 2, 3, 4]

undefined埋めの配列にmapメソッドを適用します。mapメソッドに与える関数の第二引数には配列のインデックスが渡されますので、これを返してやることで連番を生成します。

#連続する偶数の配列

JavaScript
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まで)を指定できます。

#二次元配列

JavaScript
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埋め配列の変形です。

以下はダメな例です。

JavaScript
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 ] ]

このようにしてしまうと、内側の配列は全て同じ場所を参照する配列となってしまいます。つまり以下のように一箇所の値を変更すると他の部分まで変更されてしまいます。

JavaScript
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()を用いる方法

JavaScript
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()の代わりにオブジェクトを利用する方法

JavaScript
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()と...を用いる方法

JavaScript
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またはスプレッド構文を用いています

#実用性は無い
##文字列から生成

JavaScript
Array.from("0".repeat(5)).map(i => parseInt(i))

ちなみに以下のようにすると二番目にNaNが出てきます。原因がわからないのですが、わかる方がいらっしゃればご教授いただきたいです

JavaScript
Array.from("0".repeat(5)).map(parseInt) //[ 0, NaN, 0, 0, 0 ] なぜ NaN ?

##ジェネレータで生成

JavaScript
Array.from((function*(){for(let i = 0; i < 5; i++) yield i})())

コードゴルフみたい。

#まとめ
個人的にはArray(5).fill().map(...)が好きですが、Array.from(Array(5), ...)もありかなという気がします。初投稿で拙い点が多々あったと思いますが、最後まで読んでいただきありがとうございました。٩( 'ω' )و

33
25
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?