Javaの三次元配列の入門
三次元配列は「箱の中に箱があって、その中にまた箱がある」イメージです。二次元が「表(行×列)」なら、三次元は「層×行×列」。棚の段(層)ごとに、表が並んでいる感覚で捉えるとわかりやすいです。
三次元配列の基礎イメージ
- 構造: 層・行・列の3つの軸で場所を指定する
- 添字の順番:
[層][行][列]が基本(0からスタート) - 用途の例: 3Dグリッド、時間で変わる画像フレーム、立方体データ、複数クラス×生徒×科目など
作り方(初期化)の3つの方法
1) サイズだけ決めてから値を入れる(いちばん基本)
int[][][] cube = new int[2][3][4]; // 2層・3行・4列
// 例:インデックスの合計を入れてみる
for (int z = 0; z < cube.length; z++) { // 層
for (int i = 0; i < cube[z].length; i++) { // 行
for (int j = 0; j < cube[z][i].length; j++) { // 列
cube[z][i][j] = z + i + j;
}
}
}
Java- ポイント:
lengthは階層ごとに違う可能性があるため、各段階で書く。
2) 中身も同時に書く(小さいデータ向き)
int[][][] data = {
{ // 層0
{1, 2, 3}, // 行0
{4, 5, 6} // 行1
},
{ // 層1
{7, 8, 9}, // 行0
{10, 11, 12} // 行1
}
};
Java- ポイント: 外側の
{}が「層」。その中の{}が「行」。さらに中が「列」。
3) ジャグ(三次元版)を使う(層や行でサイズが違う)
int[][][] jag = new int[2][][]; // 層数だけ決める
jag[0] = new int[2][]; // 層0は2行
jag[0][0] = new int[]{1, 2}; // 行0は2列
jag[0][1] = new int[]{3}; // 行1は1列
jag[1] = new int[1][]; // 層1は1行
jag[1][0] = new int[]{4, 5, 6}; // 行0は3列
Java- ポイント: 行・列の長さが層ごとに異なるデータを自然に表現できる。
使い方(取り出し・操作・表示)
要素を取り出す
System.out.println(data[1][0][2]); // 層1・行0・列2 → 9
Java- ポイント: 添字はそれぞれ 0 から始まる。順序を間違えない。
すべての要素を表示(基本の三重ループ)
for (int z = 0; z < data.length; z++) {
System.out.println("Layer " + z + ":");
for (int i = 0; i < data[z].length; i++) {
for (int j = 0; j < data[z][i].length; j++) {
System.out.print(data[z][i][j] + " ");
}
System.out.println();
}
System.out.println("---");
}
Java- ポイント: 見やすくするために層ごとに区切りを入れる。
実践例題で理解を深める
例題1:3Dグリッドに座標の合計を入れて可視化
目的: 各セルに「層+行+列」を入れて、構造に慣れる。
public class GridSum {
public static void main(String[] args) {
int[][][] grid = new int[2][3][4];
for (int z = 0; z < grid.length; z++) {
for (int i = 0; i < grid[z].length; i++) {
for (int j = 0; j < grid[z][i].length; j++) {
grid[z][i][j] = z + i + j;
}
}
}
for (int z = 0; z < grid.length; z++) {
System.out.println("Layer " + z + ":");
for (int i = 0; i < grid[z].length; i++) {
for (int j = 0; j < grid[z][i].length; j++) {
System.out.print(grid[z][i][j] + " ");
}
System.out.println();
}
System.out.println("---");
}
}
}
Java- ポイント: 値の規則が単純だと、添字の対応を確認しやすい。
例題2:3D版の「時間×行×列」でフレームの平均を取る
目的: 時間方向(層)に並ぶ2Dデータの、各セルの平均を計算。
public class FrameAverage {
public static void main(String[] args) {
int frames = 3, rows = 2, cols = 3;
int[][][] video = new int[frames][rows][cols];
// 適当に値を入れる(例:frame*10 + row*5 + col)
for (int t = 0; t < frames; t++) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
video[t][r][c] = t * 10 + r * 5 + c;
}
}
}
double[][] avg = new double[rows][cols]; // 各セルの時間平均
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
int sum = 0;
for (int t = 0; t < frames; t++) {
sum += video[t][r][c];
}
avg[r][c] = (double) sum / frames;
}
}
// 平均の表示
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
System.out.print(avg[r][c] + " ");
}
System.out.println();
}
}
}
Java- ポイント: 三次元から二次元へ「集約」する典型パターン。
例題3:ジャグ3Dで「層ごとに形が違う表」を扱う
目的: 現実のデータに合わせて、層ごとに行・列の数が異なる集合を安全に走査。
public class Jagged3D {
public static void main(String[] args) {
int[][][] jag = new int[2][][];
jag[0] = new int[2][];
jag[0][0] = new int[]{1, 2};
jag[0][1] = new int[]{3};
jag[1] = new int[1][];
jag[1][0] = new int[]{4, 5, 6};
for (int z = 0; z < jag.length; z++) {
System.out.println("Layer " + z + ":");
for (int i = 0; i < jag[z].length; i++) {
for (int j = 0; j < jag[z][i].length; j++) {
System.out.print(jag[z][i][j] + " ");
}
System.out.println();
}
System.out.println("---");
}
}
}
Java- ポイント: 各段階で
lengthを見て回すと範囲外を防げる。
よくあるつまずきと回避法
- 添字の順番ミス:
- 例:
[行][列][層]と書いてしまうと意図とズレる。まず「層」を決めてから「行」「列」を選ぶ流れで統一。
- 例:
- 範囲外アクセス:
- 対策: ループ条件は必ず
array.length / array[z].length / array[z][i].lengthを使う。固定値は避ける。
- 対策: ループ条件は必ず
- ジャグ配列の未初期化:
- 対策:
new int[x][][]の後は、層・行ごとにnewを忘れずに。
- 対策:
- 見づらい出力:
- 対策: 層ごとに区切り行やラベルを挟んで可読性を上げる。
便利ヘルパー:三次元配列をきれいに表示
public static void print3D(int[][][] a) {
for (int z = 0; z < a.length; z++) {
System.out.println("Layer " + z + ":");
for (int i = 0; i < a[z].length; i++) {
System.out.print("[ ");
for (int j = 0; j < a[z][i].length; j++) {
System.out.print(a[z][i][j] + (j < a[z][i].length - 1 ? ", " : ""));
}
System.out.println(" ]");
}
System.out.println("---");
}
}
Java- ポイント: デバッグで「どこに何が入っているか」を素早く確認できる。
ミニ練習問題
- 問題1: 3層・2行・3列の三次元配列を作り、
値 = 層*100 + 行*10 + 列を入れて全表示してください。 - 問題2: 時系列データ(層=時間)から、各層の合計を計算して「層ごとの合計」を表示してください。
- 問題3: ジャグ3Dで、層0は「2行(2列と1列)」、層1は「1行(3列)」にして、すべての要素の最大値を探してください。
解答と解説
問題1
3層・2行・3列の三次元配列を作り、値 = 層*100 + 行*10 + 列 を入れて全表示
解答コード
public class Practice1 {
public static void main(String[] args) {
int[][][] arr = new int[3][2][3]; // 3層・2行・3列
// 値を代入
for (int z = 0; z < arr.length; z++) { // 層
for (int i = 0; i < arr[z].length; i++) { // 行
for (int j = 0; j < arr[z][i].length; j++) { // 列
arr[z][i][j] = z * 100 + i * 10 + j;
}
}
}
// 表示
for (int z = 0; z < arr.length; z++) {
System.out.println("Layer " + z + ":");
for (int i = 0; i < arr[z].length; i++) {
for (int j = 0; j < arr[z][i].length; j++) {
System.out.print(arr[z][i][j] + " ");
}
System.out.println();
}
System.out.println("---");
}
}
}
Java解説
z*100 + i*10 + jで「層・行・列」を数字に反映。- 出力例(Layer 0 の一部):
Layer 0: 0 1 2 10 11 12 ---
問題2
時系列データ(層=時間)から、各層の合計を計算して「層ごとの合計」を表示
解答コード
public class Practice2 {
public static void main(String[] args) {
int[][][] data = {
{ {1, 2, 3}, {4, 5, 6} }, // 層0
{ {7, 8, 9}, {10, 11, 12} },// 層1
{ {13, 14, 15}, {16, 17, 18} } // 層2
};
for (int z = 0; z < data.length; z++) {
int sum = 0;
for (int i = 0; i < data[z].length; i++) {
for (int j = 0; j < data[z][i].length; j++) {
sum += data[z][i][j];
}
}
System.out.println("Layer " + z + " の合計: " + sum);
}
}
}
Java解説
- 外側ループで「層」を回す。
- 内側二重ループで「行×列」を合計。
- 出力例:
Layer 0 の合計: 21 Layer 1 の合計: 57 Layer 2 の合計: 93
問題3
ジャグ3Dで、層0は「2行(2列と1列)」、層1は「1行(3列)」にして、すべての要素の最大値を探す
解答コード
public class Practice3 {
public static void main(String[] args) {
int[][][] jag = new int[2][][];
jag[0] = new int[2][];
jag[0][0] = new int[]{5, 12}; // 層0 行0
jag[0][1] = new int[]{7}; // 層0 行1
jag[1] = new int[1][];
jag[1][0] = new int[]{20, 3, 15}; // 層1 行0
int max = jag[0][0][0]; // 最初の値で初期化
for (int z = 0; z < jag.length; z++) {
for (int i = 0; i < jag[z].length; i++) {
for (int j = 0; j < jag[z][i].length; j++) {
if (jag[z][i][j] > max) {
max = jag[z][i][j];
}
}
}
}
System.out.println("最大値: " + max);
}
}
Java解説
- ジャグ配列は「層ごとに行・列のサイズが違う」。
lengthを毎回確認しながらループするのが安全。- 出力例:
最大値: 20
まとめ
- 問題1 → 三重ループで「層・行・列」を意識。
- 問題2 → 層ごとに合計を計算する典型パターン。
- 問題3 → ジャグ配列の扱い方と「最大値探索」。
