【JavaScript】2次元配列を初心者向けにわかりやすく解説
はじめに
JavaScriptで配列を扱うとき、1次元の配列だけでは表現しきれないデータを扱いたい場面があるかもしれません。
たとえば、表形式のデータや、座標を用いた行列演算などでは、横と縦の両面でデータを整理したいと感じます。
このようなときに役立つのが2次元配列です。
2次元配列とは、配列の中にさらに配列を格納した構造を指します。
1次元配列が「一直線」に並んだリストだとすれば、2次元配列は「行」と「列」から構成されるテーブルのようなイメージです。
行列計算だけでなく、複数種類の情報をまとめて管理したいケースにも重宝します。
この記事では、JavaScriptで2次元配列を使う際に知っておきたい基本的な概念や操作方法を紹介します。
プログラミング初心者の皆さんにも理解しやすいように、用語はなるべく難しくならないよう心がけます。
実務で想定される使い方や注意点、さらには具体的なコード例も用意していますので、実際の開発シーンをイメージしながら学んでみてください。
この記事を読むとわかること
- JavaScriptにおける2次元配列の概要
- 2次元配列を操作するための基本的な方法
- 実務でよくある利用シーンと注意点
- 2次元配列を使った具体的なコード例
これらを踏まえて、2次元配列を正しく扱うためのポイントを整理し、自分の開発に応用できる知識を身につけましょう。
2次元配列とは何か
2次元配列は、「配列の中に配列が入っている」構造のことを指します。
JavaScriptで配列を扱うときは、[]
を使って1次元のリストを作成できます。
そこに、要素としてさらに配列を入れれば2次元配列が完成します。
具体的なイメージをつかみたい方は、学校の成績表を例にするとわかりやすいです。
各教科ごとに点数を記録する場合、1次元配列であれば「英語」「数学」「理科」などが横一列に並びます。
一方で、複数の生徒について同じ教科の点数を管理するときは、「生徒」を行に、「教科」を列にすると考えてみるとイメージしやすいでしょう。
つまり、生徒ごとに配列を用意して、その中に教科ごとの点数がさらに格納されるわけです。
JavaScriptでは型に厳密な制限がないため、2次元配列の要素として文字列や数値、オブジェクトなどを混在させることも可能です。
ただし、用途によってはあまりにごちゃ混ぜにすると扱いが複雑になるので、基本的には同種のデータをまとめるのがおすすめです。
2次元配列をはじめとする多次元配列は、慣れればデータを整理しやすくなります。
しかし、インデックスの取り扱いが増える分だけミスも起こりやすいので、基本的な操作に慣れることが重要です。
2次元配列の基本操作
2次元配列の基本操作は、「要素へのアクセス」「要素の追加や更新・削除」「配列を反復処理(ループ)する方法」の3つに整理できます。
こうした操作の理解を深めれば、2次元配列の応用がよりスムーズになるでしょう。
要素へのアクセス方法
JavaScriptの配列は、先頭の要素をインデックス0
とする0番目から始まります。
2次元配列の要素にアクセスするときは、行と列の両方を指定します。
たとえば、以下のような2次元配列があるとします。
const scores = [ [80, 90, 85], // 0番目の配列 [75, 88, 92], // 1番目の配列 [91, 76, 84] // 2番目の配列 ]; // 2次元配列の一要素にアクセス console.log(scores[0][1]); // 90
scores[0]
で「80, 90, 85」の配列を取得し、その後 [1]
で「90」にアクセスしています。
行列を管理するときも同様のイメージで行と列のインデックスを指定して値を取り出します。
要素の追加・更新・削除
2次元配列に対して新たな要素を追加するときは、1次元の配列で行う操作とほぼ同じです。
ただし、どの行(もしくはどの列)に追加するのかを明確にしなければなりません。
const matrix = [ [1, 2], [3, 4] ]; // 要素の追加例(2行目の末尾に5を追加) matrix[1].push(5); // [3, 4, 5] という配列が2行目になった console.log(matrix); // 要素の更新 matrix[0][1] = 9; // 1行目の2列目だった数値を9に変更 console.log(matrix); // 要素の削除(2行目の最後の要素を削除) matrix[1].pop(); console.log(matrix);
削除する場合も、特定の行にアクセスしてからpop
やsplice
などのメソッドを使えば問題ありません。
まとめて行全体を削除するときは、splice
を行に対して実行するといいでしょう。
2次元配列を反復処理する方法
2次元配列の反復処理は、外側の配列を対象にしたループと、その中にある内側の配列を対象にしたループの組み合わせになります。
よく使われる構文としては、for
文やforEach
、あるいはmap
メソッドなどがあります。
const matrix = [ [5, 6], [7, 8] ]; // for文の例 for (let i = 0; i < matrix.length; i++) { for (let j = 0; j < matrix[i].length; j++) { console.log(matrix[i][j]); } } // forEachの例 matrix.forEach(row => { row.forEach(col => { console.log(col); }); });
配列が入れ子になっている分、記述量が少し増えますが、基本は1次元配列と同じ要領です。
外側の繰り返しの中で、内側の配列をさらに繰り返すという段階的な考え方がポイントになります。
多次元配列との違い
多次元配列という言葉は、2次元配列のみならず3次元以上の配列全般を指します。
たとえば、3次元配列なら「配列の中に配列があり、その配列の中にも配列がある」という構造になります。
2次元配列と多次元配列の違いは、単に入れ子の回数の違いです。
2次元が「行」と「列」を持つなら、3次元では「奥行き」が増えたようなイメージを持つとわかりやすいでしょう。
しかし、次元が増えるほど要素へアクセスするためのインデックスが増えるので、扱いが複雑化します。
実務では、2次元配列があれば十分に対応できるケースが多いです。
たとえば、テーブルデータを扱うシーンや、座標で管理するシーンなどが該当します。
それ以上の次元を必要とするのは、3Dゲーム開発や高度な数値解析など、特定の専門分野での利用が中心となります。
2次元配列でも管理が難しいと感じるなら、オブジェクトを併用したり、クラスを使った構造化を検討することが多いでしょう。
初心者の皆さんには、まず2次元配列に慣れるところから始めるのがおすすめです。
2次元配列が実務で役立つシーン
実務で2次元配列を活用するシーンとしては、次のようなものが挙げられます。
表形式のデータ管理
大量のデータを行と列で整理したいケースです。顧客情報や在庫管理データなどを扱うときに便利です。
座標やマップ情報の管理
ゲームや位置情報関連のシステムで、マップ上の座標にオブジェクトが存在するかどうかを管理したい場合によく使われます。
行列演算
数値計算や統計処理で、行列形式のデータを扱うことがあります。科学技術計算はもちろん、画像処理などでも行列演算が登場します。
複合データの集計
部門ごとの売上や、ユーザー属性ごとのアクセス数など、カテゴリーと指標を2軸で管理する場合にも2次元配列が使われます。
2次元配列は「複数の視点」でデータを整理するときに大いに役立ちます。
表計算ソフトのシートをイメージすると、2次元配列の構造を直感的に捉えやすいでしょう。
とはいえ、複雑なロジックを扱う場合、2次元配列だけではデータの意味や関係性が分かりづらくなるかもしれません。
その場合は、データをオブジェクトとして管理したり、より柔軟に検索できる構造を考えたりする方法もあるので、現場の要件に合わせて選択することが大切です。
2次元配列の作成パターン
JavaScriptで2次元配列を作成するときは、大きく分けて静的と動的の2つのアプローチがあります。
静的な作成方法は「最初から全部のデータを確定しておく」やり方で、動的な作成方法は「必要に応じて配列を生成していく」やり方です。
静的に作成する方法
静的な作成は、あらかじめ配列の中身やサイズが決まっているときに有効です。
たとえば、3行3列の行列を予め定義しておきたい場合は、次のように書きます。
const staticMatrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ];
この段階で各要素が確定しており、サイズも固定です。
初期値があらかじめ定まっている場合は、コードが短くて分かりやすい点がメリットといえます。
一方で、サイズの変更や要素の調整が多いプロジェクトでは、都度配列を再構成しなければならないので柔軟性が低下する可能性があります。
動的に作成する方法
動的に作成する場合は、繰り返し処理などを活用して新しい配列を徐々に構築していきます。
たとえば、行数と列数がユーザーの操作で変化する場合は、この方法が向いています。
function createMatrix(rows, cols) { const matrix = []; for (let i = 0; i < rows; i++) { const rowArray = []; for (let j = 0; j < cols; j++) { rowArray.push(0); // 初期値として0を挿入 } matrix.push(rowArray); } return matrix; } // 5行×3列の2次元配列を動的に作成 const dynamicMatrix = createMatrix(5, 3); console.log(dynamicMatrix);
このように、行数と列数を引数として受け取り、内側のループで列の要素を生成します。
外側のループが終わるたびに1行分の配列を作り、最終的に2次元配列として返すイメージです。
動的な作成方法は、アプリケーションの要件に合わせて可変的に配列を扱いたいときに便利です。
ただし、実際にデータを格納するタイミングや初期値の設定などを明確にしておかないと、バグの原因になる恐れがあります。
2次元配列を使ったコード例 (行列計算)
ここでは、行列の加算や乗算など、簡単な行列演算を例にとってみます。
行列演算は、たとえば画像処理でフィルタをかけるときなど、多くの場面で利用される概念です。
// 2つの行列を要素ごとに足し合わせる関数 function addMatrices(matA, matB) { const rows = matA.length; const cols = matA[0].length; const result = []; for (let i = 0; i < rows; i++) { const row = []; for (let j = 0; j < cols; j++) { row.push(matA[i][j] + matB[i][j]); } result.push(row); } return result; } // 使用例 const matrixA = [ [1, 2], [3, 4] ]; const matrixB = [ [5, 6], [7, 8] ]; const sumMatrix = addMatrices(matrixA, matrixB); console.log(sumMatrix); // [[6, 8], [10, 12]]
このサンプルでは、同じサイズの2次元配列同士を加算しています。
加算以外の演算でも、行列のサイズが一致するかをチェックしたうえで、ループを回しながら各要素を演算すればOKです。
もし行列の乗算などを行うなら、行列の要件やアルゴリズムが少し複雑になるため、行と列の内訳を確認しながらコードを書き進めましょう。
2次元配列に慣れてくると、こうした数値計算もスムーズに扱えるようになるはずです。
2次元配列とオブジェクト配列の比較
JavaScriptでは、配列の中にオブジェクトを入れてリストを作成することも一般的です。
たとえば、ユーザー情報を管理するときに「ユーザーID」「名前」「メールアドレス」といったプロパティをオブジェクトで保持し、それらを配列としてまとめるケースがあります。
一方で、2次元配列は「行」「列」という単純明快な構造を持ちますが、要素が何を意味するかはインデックスに紐づいているため、扱う人がそのインデックスに何が入っているかを把握しておく必要があります。
2次元配列のメリット
- 行と列で整理しやすい
- データが数値のみなど単純な構造の場合に向いている
- 表やマトリックス(行列)の処理をコードで実装しやすい
オブジェクト配列のメリット
- キーと値で表現できるため、可読性が高い
- インデックスを覚えなくても、プロパティ名で直接参照が可能
- データ同士の関連性を明確に示しやすい
もし、扱うデータが「行列計算」など数値処理に特化している場合は2次元配列が向いています。
しかし、「ID」や「名前」「ステータス」など意味のある複数の情報をまとめる場合は、オブジェクト配列のほうが管理しやすいかもしれません。
実務では、2次元配列とオブジェクト配列を併用したり、場面ごとに使い分けることもあります。
2次元配列を扱うときの注意点
2次元配列は便利ですが、初心者の皆さんがつまずくポイントもいくつか存在します。
ここでは、よくある注意点を整理しておきます。
配列の初期化時の落とし穴
たとえば、下記のように1次元配列を複数作って、それをループでまとめてしまうコードを書くときに、意図せず同じ参照が使われる場合があります。
// 間違いの例 const row = [0, 0, 0]; const matrix = []; for (let i = 0; i < 3; i++) { matrix.push(row); } // すべての要素が同じ参照になってしまう matrix[0][0] = 99; console.log(matrix); // [[99, 0, 0], [99, 0, 0], [99, 0, 0]]
この場合、row
がひとつの配列参照として使い回されるため、どの行を変更してもすべての行が変更されてしまいます。
2次元配列を初期化するときは、新たな配列インスタンスを1行ずつ作ることを忘れないようにしましょう。
スパース配列の管理
JavaScriptでは、同じ行の中で要素数が異なる「スパース配列(不揃いの配列)」を作ることも可能です。
たとえば、[[1, 2], [3, 4, 5]]
のように、1行目は2つの要素、2行目は3つの要素という形式です。
このようなスパース配列は、やむを得ない場合を除きあまりおすすめできません。
要素数が不揃いだと、反復処理や行列計算のロジックが複雑になりがちです。
また、要素にアクセスしようとしたときにundefined
が返ってきて、エラーや不具合の原因になることもあります。
どうしてもスパース構造が必要なシーンでは、要素数が異なる理由や、空要素をどのように扱うかをチーム内で明確にしておくと良いでしょう。
2次元配列の応用例
2次元配列は、数値計算やテーブル管理だけではなく、いろいろな応用が可能です。
ここでは、代表的な2つの例を紹介します。
テーブルデータの表示
Webアプリケーションでテーブルを表示するとき、2次元配列のデータをそのままHTMLの<table>
タグに反映させることができます。
const tableData = [ ["商品名", "価格", "在庫"], ["りんご", 100, 50], ["バナナ", 80, 30], ["メロン", 500, 5] ]; // tableDataをHTML上に表示する場合の例 let html = "<table>"; tableData.forEach(row => { html += "<tr>"; row.forEach(cell => { html += `<td>${cell}</td>`; }); html += "</tr>"; }); html += "</table>"; // 生成したHTMLを画面に表示する処理を行う document.body.innerHTML = html;
テーブルの見出し行からデータ行までを2次元配列としてまとめておけば、for
文やforEach
で行をループしながら順番にセルを埋めるだけで表示ができます。
こうした仕組みは、画面に表示するデータを一括で管理するときや、サーバーから受け取った情報をまとめてテーブルにレンダリングするときに応用しやすいです。
画像のピクセルデータ処理
ブラウザ上でCanvasや画像データを扱うときに、ピクセルのRGB値を2次元配列や3次元配列で管理する場合があります。
たとえば、画像の横方向を行、縦方向を列としてデータを持ち、1ピクセルごとに赤・緑・青の値を配列で保持するイメージです。
こうすることで、画像をグレースケールに変換するときや、特定の色だけを抽出するときに、ピクセル単位の演算を簡単に行えるようになります。
ただし、ピクセル数が大きい画像ではデータ量が膨大になりやすいので、メモリ使用量や処理速度には気を配る必要があります。
2次元配列は、視覚的なデータや数値的なデータを「行と列」の形で扱う場面で特に力を発揮します。
2次元配列を操作するコード例(実務向け)
実務シーンでは、CSVファイルなどの外部データを取得し、それを2次元配列に変換して処理するケースが多くあります。
ここでは、CSVの読み込みから2次元配列の検索・フィルターまで、実務でよくある操作の流れを紹介します。
CSVデータから2次元配列を生成する
たとえば、"りんご,100,50\nバナナ,80,30\nメロン,500,5"
のようなテキスト形式のCSVを2次元配列にするには、行ごと・列ごとにsplit
を使います。
function csvTo2DArray(csvText) { const rows = csvText.split("\n"); const result = rows.map(row => { return row.split(","); }); return result; } // 使用例 const csvText = "りんご,100,50\nバナナ,80,30\nメロン,500,5"; const dataArray = csvTo2DArray(csvText); console.log(dataArray); // [["りんご", "100", "50"], ["バナナ", "80", "30"], ["メロン", "500", "5"]]
ここでは、改行\n
で行を分割し、その後に各行をカンマ,
で分割して配列化しています。
この結果は文字列の配列として扱われるので、価格や在庫数などを数値として扱いたい場合は、適宜parseInt
やparseFloat
を使って変換しましょう。
2次元配列の検索・フィルター
2次元配列から特定の条件に合った行だけを取り出したい場合は、1次元配列のフィルターを応用できます。
たとえば、在庫数が10以上の行だけ取得するという操作を考えてみます。
function filterByStock(dataArray, minStock) { return dataArray.filter(row => { // row例: ["りんご", "100", "50"] const stock = parseInt(row[2], 10); return stock >= minStock; }); } // 使用例 const filteredData = filterByStock(dataArray, 10); console.log(filteredData);
このように、filter
メソッドを使えば、2次元配列でも行単位の条件抽出が可能です。
ただし、コードを読む側には「row[2]が在庫数に相当する」という暗黙のルールを理解してもらわなければなりません。
データの意味づけをコードのコメントに書いたり、わかりやすい変数名にするなどの工夫が大切です。
2次元配列のパフォーマンス
2次元配列は、行と列が増えると要素数が一気に膨大になります。
たとえば、1000行 × 1000列なら、要素数は100万件に達します。
こうなると、単純なループでも処理に時間がかかったり、メモリを多く消費することがあるでしょう。
パフォーマンスに注意したいときは、以下のような観点を持つと良いです。
必要最小限のサイズで配列を作る
実際に使わない要素を大量に抱え込むと無駄が増えます。
反復処理をなるべく減らす
1回のループでまとめて処理できるロジックを工夫して、重複する走査を避けることを考えます。
スパース配列の扱いを最小限にする
不揃いの行・列が混在すると、ロジックが複雑になるだけでなく、メモリアクセスの効率が落ちることがあります。
Webブラウザで動かすコードの場合、ユーザーの体感速度を意識しながら、データ構造を見直すことも重要です。
あまりに大きなデータを扱う場合は、サーバーサイドや専用のライブラリを検討することも選択肢に入ります。
配列操作メソッドの活用
JavaScriptには、map
、filter
、reduce
など、配列を操作する便利なメソッドが多数用意されています。
2次元配列の場合は、外側の配列に対してこれらを適用し、その結果に応じて内側の配列をさらに加工するというステップを踏むことが多いです。
map, filter, reduce など
たとえば、2次元配列の各行の合計値を新たな配列として取得したい場合は、次のように書けます。
const scores = [ [10, 20, 30], [5, 15, 25], [40, 10, 10] ]; const rowSums = scores.map(row => { // rowの合計値をreduceで計算 return row.reduce((acc, val) => acc + val, 0); }); console.log(rowSums); // [60, 45, 60]
この例では、外側のmap
で各行を受け取り、行内の合計をreduce
で計算しています。
コードがシンプルになり読みやすさも向上しやすいですが、2次元配列の場合は概念的に二重ループを回しているのと同じなので、要素数が多いほど時間はかかります。
多次元配列への活用上の注意点
map
やfilter
などは、配列の性質を理解していると便利ですが、2次元配列では階層が深くなるためインデックスの指定を間違えやすいというリスクがあります。
また、1次元配列を返すのか、2次元配列を返すのかを明確にする必要があり、混乱してしまうケースもあるでしょう。
そのため、2次元配列に対してこうした高階関数を使うときは、いきなり難しい操作を組み合わせるのではなく、1段階ずつ処理を確認しながら進める方法が安全です。
テストやデバッグ時には、途中経過でconsole.log
を使い、想定通りの結果が得られているかをチェックすると良いでしょう。
2次元配列に限らず、配列操作メソッドは意図しない結果を生むことがあります。とくに構造が深いほど勘違いが生じやすいので、段階的に出力を確かめながら進めると安心です。
まとめ
JavaScriptで2次元配列を使うと、表形式のデータや行列計算、画像のピクセル情報などを整理して扱いやすくなります。
初期化時の落とし穴やスパース配列など、注意が必要なポイントはありますが、基本的な操作自体は1次元配列を応用すれば乗り越えられます。
実務では、配列のサイズや要素数が増えるにつれて、可読性やパフォーマンスが課題になることもあるでしょう。
そのため、2次元配列を採用するときは「配列を使う目的」や「扱うデータの種類」を明確にして、最適なデータ構造を選ぶ姿勢も大切です。
もし、より複雑なデータ管理が必要な場合は、オブジェクト配列やライブラリの導入、データベースとの連携などを検討してみるのも一手です。
2次元配列の操作に慣れれば、行列演算や大規模データの集計も扱いやすくなるはずです。
2次元配列を正しく使いこなすためには、行と列を明確に意識し、データの意味を整理することが何よりも大切です。インデックスの管理と活用シーンをきちんと把握し、トラブルを未然に防ぎましょう。