Posted at

2次元配列の初期化(ES2015)

More than 1 year has passed since last update.


1次元配列の初期化

配列を new Array で生成すると、各要素が undefined の配列が得られます。

ES2015では fill メソッドを用いることで、引数の値で初期化してくれます。

var arr = (new Array(3)).fill(0);


2次元配列の初期化

それでは、3×3の2次元配列を0で初期化するコードを紹介します。


従来の方法

これまでのJavaScriptでは、配列を2重ループを用いて初期化するのが定番でしたね。


es5.js

var x, y;

var tbl = new Array(3);
for(y = 0; y < 3; y++) {
tbl[y] = new Array(3);
for(x = 0; x < 3; x++) {
tbl[y][x] = 0;
}
}

実際のところ、これで充分なのですが、ES2015の書式でもっとすっきりさせてみたいと思います。


失敗例


failed.js

var tbl = (new Array(3)).fill((new Array(3)).fill(0));


冒頭の1次元配列でのfillを使った書き方に倣って、fillを2重にしてみました。

最初書いてみて、これで万事OK、と思っていたのですが、実際このコードには欠陥があります。

var tbl = (new Array(3)).fill((new Array(3)).fill(0));

tbl[1][1] = 5;
console.log(tbl[1][1]); // => 5
console.log(tbl[2][1]); // => 5

このコードのように、2次元配列内の要素を1つ上書きしただけのはずなのに、

違う行の要素まで書き換わってしまっています。

それもそのはず、fillの中に入れた配列がプリミティブ値でないため、参照が各行とも同じになってしまっているのです。

以下のコードとやってることは同じです。

var row = (new Array(3)).fill(0);

var tbl = [row, row, row];
row[1] = 5;
console.log(tbl[1][1]); // => 5
console.log(tbl[2][1]); // => 5


正しい書き方


方法1

最初に試した方法を利用します。


method-1.js

var tbl = JSON.parse(JSON.stringify((new Array(3)).fill((new Array(3)).fill(0))));


配列をいったんJSON化して、それを再度オブジェクト化することによって、全ての配列が別オブジェクトになります。


方法2

いったん1×3の配列を作り、それぞれの行を forEach を使って配列にすげ替えます。


method-2.js

var tbl = (new Array(3)).fill(0);

tbl.forEach((_, i) => {
tbl[i] = (new Array(3)).fill(0);
});

あまり効率的な感じはしませんね…。


方法3

これが一番素直でよいでしょう。


method-3.js

var tbl = new Array(3);

for(let y = 0; y < 3; y++) {
tbl[y] = new Array(3).fill(0);
}

ES2015の記法で1重ループに抑えることができました。

他にもっとすっきりした初期化方法があればコメントください。