JavaScript 入門

JavaScript 多次元配列

JavaScriptの多次元配列は、配列の概念を拡張し、配列の内部にさらに配列を作成することを可能にします。これにより、テーブル(表)やマトリックス(行列)のようなグリッド状の構造でデータを保存・操作できるようになります。

多次元配列を使用すれば、複数の次元やカテゴリを持つデータを整理でき、複雑な関係性の表現や高度なデータ処理が容易になります。

1. 多次元配列を理解する

多次元配列は、本質的には「配列の配列」です。つまり、メインの配列に含まれる各要素自体が別の配列であることを意味します。これらの内部配列にはさらに配列を含めることができ、任意の深さの構造を作成可能です。

3次元以上の配列も作成できますが、最も一般的で視覚化しやすいのは2次元配列です。

2. 多次元配列の作成

JavaScriptでは、配列を互いに入れ子(ネスト)にすることで多次元配列を作成します。以下は、基本的な2次元配列を作成する例です。

// 行列を表す2次元配列を作成
let matrix = [
  [1, 2, 3], // 1行目 (インデックス 0)
  [4, 5, 6], // 2行目 (インデックス 1)
  [7, 8, 9]  // 3行目 (インデックス 2)
];

console.log(matrix);

この例では、matrix は3つの要素を持つ配列です。これら3つの要素のそれぞれが、3つの数値を含む配列になっています。これを「3行3列のテーブル」とイメージしてください。

3. 多次元配列の要素へのアクセス

多次元配列の要素にアクセスするには、複数のインデックスを使用します。最初のインデックスで行を指定し、2番目のインデックスで列を指定します。JavaScriptの配列はゼロベース(0から始まる)であることを忘れないでください。

// 行列内の要素にアクセス
console.log(matrix[0][0]); // 出力: 1 (0行目 0列目の要素)
console.log(matrix[1][2]); // 出力: 6 (1行目 2列目の要素)
console.log(matrix[2][1]); // 出力: 8 (2行目 1列目の要素)

4. 多次元配列の要素の修正

特定のインデックスに新しい値を代入することで、要素を修正できます。

// 行列内の要素を修正
matrix[1][1] = 10; // 1行目 1列目の要素を 10 に変更
console.log(matrix[1][1]); // 出力: 10
console.log(matrix);

5. 多次元配列の走査(ループ処理)

多次元配列のすべての要素を処理するには、通常入れ子になったループ(ネストされたループ)を使用します。外側のループで行を走査し、内側のループで列を走査します。

// 入れ子のループを使用して行列を走査
for (let i = 0; i < matrix.length; i++) {
  for (let j = 0; j < matrix[i].length; j++) {
    console.log(`${i}行目 ${j}列目の要素: ${matrix[i][j]}`);
  }
}

このコードの仕組み:

  • 外側ループ (i): 0 から matrix.length - 1 まで繰り返され、行を代表します。
  • 内側ループ (j): 0 から matrix[i].length - 1 まで繰り返され、現在の行内の列を代表します。
  • matrix[i][j] で、指定した行と列の要素にアクセスします。

6. 行の長さが異なる多次元配列(ジャグ配列)

すべての行が同じ列数を持つ「矩形配列」が一般的ですが、JavaScriptでは行ごとに長さが異なる配列を作成することも可能です。これは「ジャグ配列(Jagged Arrays)」と呼ばれます。

// ジャグ配列を作成
let jaggedArray = [
  [1, 2],
  [3, 4, 5, 6],
  [7]
];

console.log(jaggedArray);

// ジャグ配列を走査
for (let i = 0; i < jaggedArray.length; i++) {
  for (let j = 0; j < jaggedArray[i].length; j++) {
    console.log(`${i}行目 ${j}列目の要素: ${jaggedArray[i][j]}`);
  }
}

7. 多次元配列の一般的な操作

7.1 要素の合計

配列内のすべての数値の合計を計算します。

let matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];

let sum = 0;

for (let i = 0; i < matrix.length; i++) {
  for (let j = 0; j < matrix[i].length; j++) {
    sum += matrix[i][j];
  }
}

console.log("全要素の合計:", sum); // 出力: 45

7.2 最大要素の探索

配列内から最大値を見つけ出します。

let matrix = [
  [1, 2, 3],
  [4, 9, 6],
  [7, 8, 5]
];

let max = matrix[0][0]; // 最初の要素を暫定の最大値とする

for (let i = 0; i < matrix.length; i++) {
  for (let j = 0; j < matrix[i].length; j++) {
    if (matrix[i][j] > max) {
      max = matrix[i][j];
    }
  }
}

console.log("最大要素:", max); // 出力: 9

7.3 行列の転置

行と列を入れ替えた新しい行列を作成します。

let matrix = [
  [1, 2, 3],
  [4, 5, 6]
];

function transpose(matrix) {
  let rows = matrix.length;
  let cols = matrix[0].length;
    
  // 次元の入れ替わった新しい配列を作成
  let transposedMatrix = [];
    
  for (let j = 0; j < cols; j++) {
    transposedMatrix[j] = []; // 新しい行を初期化
    for (let i = 0; i < rows; i++) {
      transposedMatrix[j][i] = matrix[i][j];
    }
  }
  return transposedMatrix;
}

let transposed = transpose(matrix);
console.log("元の行列:", matrix);
console.log("転置行列:", transposed);

8. 実践的な例とデモンストレーション

8.1 示例 1:ゲームボードの表現

多次元配列は、三目並べ(Tic-Tac-Toe)やチェスなどのゲームボードを表現するのに最適です。

// 三目並べのボードを表現
let ticTacToeBoard = [
  ['X', 'O', ' '],
  [' ', 'X', ' '],
  ['O', ' ', 'X']
];

// ボードをプリントする関数
function printBoard(board) {
  for (let i = 0; i < board.length; i++) {
    console.log(board[i].join('|')); // 垂直線で要素を繋ぐ
    if (i < board.length - 1) {
      console.log('-----'); // 行間の区切り線
    }
  }
}

printBoard(ticTacToeBoard);

8.2 示例 2:学生の成績データの保存

複数の学生による複数の科目の成績を保存・管理できます。

// 学生の成績データを保存
let studentGrades = [
  ['Alice', 85, 90, 92],   // 学生 1: 名前, 点数1, 点数2, 点数3
  ['Bob', 78, 88, 80],     // 学生 2: 名前, 点数1, 点数2, 点数3
  ['Charlie', 92, 95, 88]  // 学生 3: 名前, 点数1, 点数2, 点数3
];

// 平均点を計算する関数
function calculateAverageGrade(student) {
  let sum = 0;
  // インデックス 0 は名前なので、1 からループを開始
  for (let i = 1; i < student.length; i++) {
    sum += student[i];
  }
  return sum / (student.length - 1); // 名前を除いた数で割る
}

// 各学生の名前と平均点を出力
for (let i = 0; i < studentGrades.length; i++) {
  let student = studentGrades[i];
  let name = student[0];
  let averageGrade = calculateAverageGrade(student);
  console.log(`${name} の平均点: ${averageGrade.toFixed(2)}`);
}

8.3 示例 3:数学的な行列演算(行列の積)

多次元配列は、数学的な行列演算にも頻繁に利用されます。

// 行列の積を計算する関数
function matrixMultiply(matrixA, matrixB) {
    let rowsA = matrixA.length;
    let colsA = matrixA[0].length;
    let rowsB = matrixB.length;
    let colsB = matrixB[0].length;

    // 行列の積が定義される条件を確認
    if (colsA !== rowsB) {
        return "行列を掛け合わせることができません。次元が不一致です。";
    }

    // 結果を格納する行列をゼロで初期化
    let resultMatrix = Array(rowsA).fill(null).map(() => Array(colsB).fill(0));

    // 積の計算を実行
    for (let i = 0; i < rowsA; i++) {
        for (let j = 0; j < colsB; j++) {
            for (let k = 0; k < colsA; k++) {
                resultMatrix[i][j] += matrixA[i][k] * matrixB[k][j];
            }
        }
    }
    return resultMatrix;
}

// 実行例
let matrixA = [[1, 2], [3, 4]];
let matrixB = [[5, 6], [7, 8]];

let product = matrixMultiply(matrixA, matrixB);
console.log("行列 A:", matrixA);
console.log("行列 B:", matrixB);
console.log("行列の積:", product);