1. ジャグ配列は2次元配列と異なる
ついに多くの人が「ジャグ配列」と呼ぶテーマに到達しました。英語では jagged arrays と言います。2次元配列と違い、ジャグ配列では各行の長さをバラバラにできます。たとえばマンション群があって、棟ごとに部屋数が違うようなものです — ある棟は5戸、別の棟は20戸、そして3つ目は1戸だけ、という具合です。
ジャグ配列とは、各要素自体が配列であり、かつ内側の配列(「サブ配列」とも呼ばれます)の長さがそれぞれ異なっていてよい配列のことです。
主な違い:
- 2次元配列では各「行」(および各「列」)の要素数が同じです。 例: int[][] grid = new int[3][5]; — 常に3行で各行に5要素あります。
- ジャグ配列では各行の長さを変えられます。 例: int[][] jagged = new int[3][]; — そして後で各行(サブ配列)をそれぞれ別々に初期化します。
見た目はこうなります:
2次元配列 (3x3):
┌───┬───┬───┐
│ 1 │ 2 │ 3 │
├───┼───┼───┤
│ 4 │ 5 │ 6 │
├───┼───┼───┤
│ 7 │ 8 │ 9 │
└───┴───┴───┘
ジャグ配列(長さが異なる):
┌───┬───┐
│ 1 │ 2 │
├───┼───┼───┬───┐
│ 3 │ 4 │ 5 │ 6 │
├───┼───┴───┴───┘
│ 7 │
└───┘
2. ジャグ配列の宣言と初期化の構文
ジャグ配列の宣言は、これまでの型と比べて何も怖くありません。二重の角かっこに怯える必要はありません:
int[][] jaggedArray = new int[3][];
これは、3要素からなる配列があり、その各要素が int の配列であることを意味します。ただし、まだ内側の配列は作られていません。よりよく理解するために、もう少し詳しく見てみましょう。
ジャグ配列を段階的に初期化する
ステップ1 — 外側(トップレベル)配列の作成:
int[][] jaggedArray = new int[3][];
これで「行」が3つありますが、どれもまだ null です。
ステップ2 — 内側の配列(サブ配列)の作成と長さの設定:
たとえば、1行目の長さを2、2行目を4、3行目を3にします:
jaggedArray[0] = new int[2]; // 1行目は2要素
jaggedArray[1] = new int[4]; // 2行目は4要素
jaggedArray[2] = new int[3]; // 3行目は3要素
ステップ3 — 値の代入:
内側の配列も普通の配列です。たとえば:
jaggedArray[0][0] = 1;
jaggedArray[0][1] = 2;
jaggedArray[1][0] = 3;
jaggedArray[1][1] = 4;
jaggedArray[1][2] = 5;
jaggedArray[1][3] = 6;
jaggedArray[2][0] = 7;
jaggedArray[2][1] = 8;
jaggedArray[2][2] = 9;
ジャグ配列の簡潔な初期化
値があらかじめ分かっているなら、その場で生成と初期化ができます:
int[][] jaggedArray = new int[][]
{
new int[] { 1, 2 },
new int[] { 3, 4, 5, 6 },
new int[] { 7, 8, 9 }
};
あるいは、内側配列の型を省略してもう少し短く書けます:
int[][] jaggedArray =
{
{ 1, 2 },
{ 3, 4, 5, 6 },
{ 7, 8, 9 }
};
3. ジャグ配列の走査と操作
ジャグ配列の走査は2次元配列と同じくらい簡単ですが、外側のループが行を、内側のループがその行の要素(長さが行ごとに異なる)を回る点に注意します:
for (int i = 0; i < jaggedArray.length; i++)
{
System.out.println("行 " + i + ":");
for (int j = 0; j < jaggedArray[i].length; j++)
{
System.out.print(jaggedArray[i][j] + " ");
}
System.out.println();
}
出力結果:
行 0:
1 2
行 1:
3 4 5 6
行 2:
7 8 9
for-each を使えば、インデックスを気にせずに書けます:
for (int[] row : jaggedArray)
{
for (int value : row)
{
System.out.print(value + " ");
}
System.out.println();
}
4. ジャグ配列の典型的な用途
どんなときに2次元配列よりジャグ配列が有用でしょうか?
- 各ユーザーごとにデータ点の数が異なる場合(科目ごとの成績、購入履歴、コメントなど)。
- データが三角形や段状の構造をしている場合(ピラミッド表示、パスカルの三角形など)。
- メモリを節約したい場合。2次元配列ではすべての行が固定長ですが、ジャグ配列なら必要な分だけ確保できます。
身近な例: 学生の成績マネージャー
学生が3人いて、数学の課題ごとの点数が次のように違っているとします:
| 学生 | 点数 |
|---|---|
| 0 | 5, 4 |
| 1 | 3, 4, 4 |
| 2 | 5 |
このように配列を宣言します:
int[][] studentMarks = new int[3][];
studentMarks[0] = new int[] { 5, 4 }; // 1人目の学生 — 2件の点数
studentMarks[1] = new int[] { 3, 4, 4 }; // 2人目の学生 — 3件の点数
studentMarks[2] = new int[] { 5 }; // 3人目の学生 — 1件の点数
各学生の点数を出力します:
for (int i = 0; i < studentMarks.length; i++)
{
System.out.print("学生 " + i + ": ");
for (int j = 0; j < studentMarks[i].length; j++)
{
System.out.print(studentMarks[i][j] + " ");
}
System.out.println();
}
他の型でもジャグ配列
ジャグ配列は何にでもできます。文字列、さらに深い配列の配列、あなたのクラスのオブジェクトでも構いません。
例: 文字列配列
String[][] groups = {
{ "イワン", "ピョートル" },
{ "マリア", "アレクセイ", "セルゲイ" },
{ "ヴァシリーサ" }
};
5. 3次元配列と多次元配列
配列についてのもうひとつ興味深い事実です。2次元配列が作れるなら、3次元配列も作れるのではないでしょうか。
はい、任意の次元数の配列を作成できます。このような配列を多次元配列と呼びます。
多次元配列の宣言方法
必要な次元数だけ角かっこを並べて指定します:
int[][][] cube = new int[2][3][4]; // 2「層」、3行、4列
cube[0][1][2] = 99;
これは3次元配列です:
- 第1軸に2要素、
- 第2軸に3要素、
- 第3軸に4要素。
この配列は、連続領域に詰め込まれた大きな「データのキューブ」です。
3次元配列の走査
要素へはすべての添字を指定してアクセスします:
for (int i = 0; i < cube.length; i++)
{
for (int j = 0; j < cube[i].length; j++)
{
for (int k = 0; k < cube[i][j].length; k++)
{
System.out.print(cube[i][j][k] + " ");
}
System.out.println();
}
System.out.println("---");
}
- 添字は Java ではいつもどおり 0 から始まります。
- この配列の要素総数は 2 × 3 × 4 = 24 です。
多次元配列の実用例
- 2D — 表、チェス盤、画像。
- 3D — コンピュータグラフィックスのボクセル、科学計算用データ(例: 時空間の各点の温度)。
- 4D 以上 — あまり使われませんが、高度な数学、シミュレーション、機械学習などで登場します。
6. 多次元配列を扱う際の典型的な誤り
エラー1: 配列の範囲外アクセス
最もよくあるのは、存在しない要素にアクセスしようとすることです。例えば:
int[][] arr = new int[2][3];
arr[2][0] = 5; // エラー! インデックス2の行は存在しない(0 と 1 だけ)
arr[0][3] = 7; // エラー! インデックス3の列は存在しない(0, 1, 2 だけ)
このようなアクセスでは ArrayIndexOutOfBoundsException がスローされます。添字が有効範囲(0 から length - 1)内にあることを常に確認しましょう。
エラー2: ジャグ配列で内側の配列を未初期化のまま使う
ジャグ配列を作って内側の配列を初期化し忘れると、アクセス時に NullPointerException になります:
int[][] jagged = new int[3][];
jagged[0][0] = 5; // エラー! jagged[0] == null
まずは内側の配列を作成する必要があります: jagged[0] = new int[2];
エラー3: 配列の長さの使い方を誤る
matrix.length(行数)と matrix[0].length(列数)を取り違えるケースがよくあります。特にコピー、走査、列方向の合計などで発生します。
エラー4: すべての行が同じ長さだと思い込む
ジャグ配列では行の長さはバラバラです。matrix[i][j] にアクセスする場合は、j < matrix[i].length を確認しましょう。
エラー5: 添字の順序を取り違える
「先に行、次に列」という順序を取り違えることがあります。つまり matrix[行][列] の順です。逆ではありません。
GO TO FULL VERSION