HOWTO · JavaScript

JavaScript の 2 次元配列

このチュートリアルでは、JavaScript で 2 次元の配列を宣言する方法を紹介します。

このページの内容

JavaScriptの2次元配列は、要素として行配列を持つ配列です。値が決まっている場合は入れ子のリテラルを使い、行数や値がデータによって決まる場合はループ、Array.from()、またはArray.prototype.map()で行を個別に作成します。セルは2つのインデックスで読み取ります。grid[rowIndex][columnIndex]のように指定します。

JavaScriptの2次元配列とは?

JavaScriptには独立した2次元配列型はありません。グリッドは配列の配列として表し、外側の配列が行を保持し、各行がセルを保持します。この構造は行列、ゲーム盤など、行と列で構成されるデータに使えます。行ごとに長さが異なることもあるため、矩形である保証がない場合は各行の長さを確認してください。

配列のインデックスは0から始まります。grid[1][2]では、1が2行目を、2がその行の3番目のセルを示します。行の作成とセルへの値の設定は別の手順です。新しく確保した配列には未初期化のスロットが含まれることがあり、これはnullを設定したセルとは異なります。

入れ子の配列リテラルで2次元配列を作成する

値が決まっている固定のグリッドでは、各行を内側の配列として記述します。

const grid = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];

console.log(grid[0][1]);

各内側の配列がそれぞれ独立した行になります。grid[0][1]は値2を選択します。最初のインデックスで行を選び、2番目のインデックスでその行のセルを選びます。データ全体がすでに揃っている場合は、リテラル表記が便利です。

ループで2次元配列を作成する

行数やセルの値が実行時に決まる場合は、入れ子のループを使います。外側のループを繰り返すたびに新しい行を確保し、その後で各セルに値を代入します。

const rows = 3;
const columns = 3;
const grid = [];

for (let row = 0; row < rows; row++) {
  grid[row] = [];
  for (let column = 0; column < columns; column++) {
    grid[row][column] = row * columns + column + 1;
  }
}

console.log(grid);

外側のループで、互いに独立した3つの行を作成します。内側のループでは、各行に1から9までの値を入れます。セルを既定値で初期化する場合は、grid[row][column] = 0のように内側のループで代入します。

変更する行に対してArray(rows).fill(Array(columns).fill(0))を使うのは避けてください。fill()は同じ行への参照を繰り返すため、1つの行を変更すると、すべての行でその列の値が変わったように見えます。外側のループを繰り返すたびに新しい行を作成してください。

Array.from()で2次元配列を作成する

Array.from()を使うと、外側の配列と、各インデックスに対応する新しい行を作成できます。マッピング用コールバックには現在のインデックスが渡されるため、行と列の位置に基づいて各セルの値を計算できます。

const rows = 3;
const columns = 3;
const grid = Array.from({ length: rows }, (_, row) =>
  Array.from({ length: columns }, (_, column) => row * columns + column + 1)
);

console.log(grid);

外側の呼び出しで3つの行を作成し、内側の呼び出しで各行を作成して3つの値を入れます。内側のArray.from()は外側の各インデックスについて1回ずつ実行されるため、各行は別々の配列です。すべてのセルを0で始めるには、内側の呼び出しにArray.from({ length: columns }, () => 0)を使います。

Array.prototype.map()で2次元配列を作成する

map()は、配列にすでに存在する要素を変換して新しい配列を作ります。コールバックがすべての行について実行されるよう、要素が存在するスロットを持つ配列から始めてください。new Array(rows)だけでは疎なスロットが作られ、map()はそれらをスキップします。

const rows = 3;
const columns = 3;
const grid = Array.from({ length: rows }, (_, row) => row).map(row =>
  Array.from({ length: columns }, (_, column) => row * columns + column + 1)
);

console.log(grid);

ここでは、まずArray.from()で行インデックスの要素が存在する配列を作り、Array.prototype.map()で各インデックスに対して個別に確保した行を1つずつ作ります。コールバックから既定値を入れた行を返すこともできます。たとえば、Array.from({ length: columns }, () => 0)を使います。

2次元配列の値を初期化してアクセスする

セルを読み取るにはgrid[row][column]を使い、更新するには同じインデックスを通して代入します。たとえばgrid[1][2] = 42のようにします。3行4列の配列では、有効な行インデックスは0から2、列インデックスは0から3です。JavaScriptは配列の行数や列数を矩形に保つわけではないため、各行の長さによって使用できる列インデックスが決まります。

グリッド内のすべてのセルを同じ値で初期化する場合は、行インデックスごとに新しい行を作成します。たとえば、Array.from({ length: rows }, () => Array.from({ length: columns }, () => 0))を使うと、各セルが0に設定された別々の行ができます。これは疎なスロットを持つnew Array(rows)や、fill()で1つの内側の配列を繰り返す方法とは異なります。

値が決まっている場合はリテラル、構築を明示的に制御したい場合はループ、行やセルを生成する場合はArray.from()、要素が存在する配列を変換する場合はArray.prototype.map()を選びます。どの方法でも通常の入れ子配列が作られ、セルには同じ行・列の順でアクセスして更新できます。