多次元配列とは何か
多次元配列は「配列の中に配列を入れた構造」です。2次元は行と列、3次元はさらに“層”があるイメージになります。ここが重要です:JavaScriptには専用の多次元型はなく、配列の入れ子で表現します。つまり [ [1,2], [3,4] ] のように“配列の要素がまた配列”です。
作り方とアクセス(2次元の基本)
二次元配列の生成と参照
const grid = [
[1, 2, 3], // 0行目
[4, 5, 6], // 1行目
[7, 8, 9] // 2行目
];
console.log(grid[0][0]); // 1(0行0列)
console.log(grid[1][2]); // 6(1行2列)
console.log(grid[2][1]); // 8(2行1列)
JavaScriptここが重要です:インデックスは常に 0 始まり。行は最初の []、列は次の [] で参照します。行数は grid.length、各行の列数は grid[row].length で取り出します。
初期化の安全なやり方(繰り返しで埋める)
const rows = 3, cols = 4;
const matrix = Array.from({ length: rows }, () =>
Array.from({ length: cols }, () => 0)
);
JavaScriptここが重要です:Array(rows).fill(Array(cols).fill(0)) だと“同じ行配列の参照が複製”されてしまい、1行を変えると全行が変わる事故になります。必ず行ごとに新しい配列を作成しましょう。
反復処理(行と列を正しくループする)
二重ループで全要素を処理
for (let r = 0; r < grid.length; r++) {
for (let c = 0; c < grid[r].length; c++) {
const v = grid[r][c];
console.log(`(${r},${c}) = ${v}`);
}
}
JavaScriptここが重要です:外側が行、内側が列。行によって列数が違う“不揃い(ジャグ配列)”でも安全に回すため、常に grid[r].length を基準にします。
entries と for…of で読みやすく
for (const [r, row] of grid.entries()) {
for (const [c, v] of row.entries()) {
console.log(`(${r},${c}) = ${v}`);
}
}
JavaScriptここが重要です:entries() を使うとインデックスと値を同時に扱え、可読性が上がります。境界条件のミスも減ります。
変更・変換・集計(実用的な操作)
要素の更新(座標指定で書き換え)
grid[1][1] = 99; // 1行1列を 99 に
JavaScriptここが重要です:範囲外アクセスは undefined になるため、必ず行・列の境界チェックを行うと安全です。
全要素を変換(map の二段重ね)
const doubled = grid.map(row => row.map(v => v * 2));
JavaScriptここが重要です:非破壊で“同じ形の新配列”を作れます。状態管理(React/Vue)でも推奨される書き方です。
行・列の合計を計算
const rowSums = grid.map(row => row.reduce((acc, v) => acc + v, 0));
const colSums = Array.from({ length: grid[0].length }, (_, c) =>
grid.reduce((acc, row) => acc + row[c], 0)
);
JavaScriptここが重要です:行の集計は行ごとに reduce、列は“列インデックスで縦に畳む”のが定石です。
行列操作(転置・積などの基礎)
転置(行と列を入れ替える)
function transpose(m) {
const rows = m.length;
const cols = m[0].length;
return Array.from({ length: cols }, (_, c) =>
Array.from({ length: rows }, (_, r) => m[r][c])
);
}
const t = transpose(grid);
JavaScriptここが重要です:元が R×C の行列なら、転置は C×R になります。列数が行によって違う場合は先に整形しましょう。
行列積(A: R×K と B: K×C の積)
function multiply(A, B) {
const R = A.length, K = A[0].length, C = B[0].length;
return Array.from({ length: R }, (_, r) =>
Array.from({ length: C }, (_, c) =>
Array.from({ length: K }, (_, k) => A[r][k] * B[k][c])
.reduce((acc, x) => acc + x, 0)
)
);
}
JavaScriptここが重要です:積の定義は「A の行と B の列の内積」。次元が一致していないと計算できないので、R×K と K×C を必ず確認します。
ジャグ(不揃い)配列と実務での注意
不揃い配列の例と安全な扱い
const jagged = [
[1, 2, 3],
[4, 5], // 列数が少ない
[6] // さらに少ない
];
for (let r = 0; r < jagged.length; r++) {
for (let c = 0; c < jagged[r].length; c++) {
console.log(jagged[r][c]);
}
}
JavaScriptここが重要です:列数が行ごとに異なる前提なら、“その行の列長”に合わせて処理します。固定表のように扱うと範囲外参照のバグになります。
安全な初期化・コピー
// 浅いコピー(行ごとの新配列を作る)
const copy = grid.map(row => row.slice());
// 深いコピー(入れ子まで完全に独立)
const deep = structuredClone(grid);
JavaScriptここが重要です:多次元は“浅いコピーだと中の配列参照が共有”されます。行ごとに slice、または structuredClone で深いコピーを取り、意図しない連動を防ぎます。
現実の活用例(表・座標・迷路・画像)
表データ(レンダリングやCSV扱い)
const rows = [
["品名", "価格"],
["ペン", "120"],
["ノート", "300"]
];
const html = rows.map(r => `<tr>${r.map(c => `<td>${c}</td>`).join("")}</tr>`).join("");
document.querySelector("tbody").innerHTML = html;
JavaScriptここが重要です:二次元配列は“行×列”の表現に直感的。map の二段重ねで行→セルへ展開できます。
座標グリッド(迷路やゲーム盤)
const W = 5, H = 5;
const board = Array.from({ length: H }, () => Array.from({ length: W }, () => 0));
board[2][3] = 1; // 障害物
JavaScriptここが重要です:盤面や迷路は 0/1 などで格納し、座標で更新・探索します。境界チェックを徹底すると安定します。
画像処理の基礎(ピクセルの2次元)
ピクセルの行列として扱い、フィルタや畳み込みを適用します。実務では TypedArray や Canvas の ImageData と併用しますが、概念は“二次元の配列”です。
よくある落とし穴と回避策
意図せず Array(rows).fill(…) を使って同じ行配列を共有し、1行の変更が全行に波及する事故が頻発します。必ず行ごとに新しい配列を生成してください。不揃い配列を固定長として扱うと範囲外参照で undefined を踏みます。各行の length を見るループにしましょう。二次元のコピーは浅いコピーだと行の参照共有が残ります。構造を保った非破壊変換には row.map、完全独立には structuredClone を選びます。行列操作(転置・積)は“次元の整合”が命で、R×K と K×C を毎回確認するとバグが消えます。
まとめ
多次元配列は「配列の入れ子」で、2次元なら行×列として扱います。安全な初期化は Array.from を二段重ね、アクセスは [row][col]、反復は行の length を基準に。変換は map の二段重ね、集計は reduce と縦畳み、行列の転置・積は次元の整合が鍵です。ジャグ配列は“行の列長に合わせる”、コピーは浅いと参照共有、深いなら structuredClone。これらを押さえれば、初心者でも二次元データを直感的に扱え、応用(表、座標、画像)へ自信を持って広げられます。
