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

  • 3
    Like
  • 3
    Comment
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重ループに抑えることができました。

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