ジャグ配列(配列の配列)とは
C#には、2次元の表形式データを扱う配列として、「2次元配列(int[,])」と「ジャグ配列(int[][])」の2種類があります。
2次元配列(int[,])が、常に行と列の数が揃った「格子状(グリッド)」のデータ構造であるのに対し、ジャグ配列は「配列の配列(Array of Arrays)」とも呼ばれます。
ジャグ配列の最大の特徴は、内部の各配列(行)が、それぞれ異なる長さ(列数)を持つことができる点です。例えば、1行目には3個の要素、2行目には5個の要素、といった柔軟なデータ構造を実現できます。
この記事では、ジャグ配列の宣言、初期化、および要素へのアクセス方法について解説します。
ジャグ配列の宣言と初期化
ジャグ配列の型は int[][] のように、[]を2つ続けて記述します。
1. 宣言と同時に初期化する (推奨)
最も一般的で読みやすい方法は、宣言と同時にnewキーワードと{}(初期化子)を使って、内部の配列を定義してしまう方法です。
using System;
public class JaggedArrayInitExample
{
public static void Main()
{
// string のジャグ配列 (string[][])
// 各プロジェクトが持つタスクリスト(タスク数が異なる)
string[][] projectTasks = new string[][]
{
new string[] { "Design UI", "Implement Login" }, // 1番目の配列 (要素数 2)
new string[] { "Setup Database" }, // 2番目の配列 (要素数 1)
new string[] { "Test API", "Write Docs", "Deploy" } // 3番目の配列 (要素数 3)
};
// 型推論 (var) を使用した簡略構文
// var projectTasks = new []
// {
// new [] { "Design UI", "Implement Login" },
// new [] { "Setup DB" },
// new [] { "Test API", "Write Docs", "Deploy" }
// };
Console.WriteLine("--- 宣言と同時に初期化 ---");
// 3番目の配列 (インデックス 2) の、2番目の要素 (インデックス 1)
Console.WriteLine($"プロジェクトCのタスク2: {projectTasks[2][1]}"); // "Write Docs"
}
}
2. 内部配列を個別に初期化する
先に「外側の配列」のサイズ(行数)だけを決定し、後から「内側の配列」(各行)を個別にnewで作成する方法もあります。
using System;
public class JaggedArraySeparateInit
{
public static void Main()
{
// 3日分の売上データを格納するジャグ配列を宣言 (外側は 3)
int[][] dailySales = new int[3][];
// 日によってデータ件数が異なる場合
dailySales[0] = new int[] { 100, 150 }; // 1日目は2件
dailySales[1] = new int[] { 200, 210, 180 }; // 2日目は3件
dailySales[2] = new int[] { 300 }; // 3日目は1件
// 2日目 (インデックス 1) の 3件目 (インデックス 2)
Console.WriteLine($"2日目の3件目の売上: {dailySales[1][2]}"); // 180
}
}
ジャグ配列の要素へのアクセス
ジャグ配列の要素へのアクセスは、2次元配列の[行, 列]とは異なり、[行][列] のように[]を2つ続けて記述します。
myArray[i] は「i番目の内側の配列」を指し、myArray[i][j] は「i番目の配列の、j番目の要素」を指します。
ジャグ配列のループ処理
ジャグ配列のすべての要素を処理(反復処理)するには、ループを2重(ネスト)にする必要があります。
1. for ループによる反復処理
forループを使用する場合、内側のループの条件式(j)に注意が必要です。2次元配列([,])ではGetLength(1)(列数)を使いますが、ジャグ配列([][])では**myArray[i].Length**(i番目の内側配列の長さ)を使用します。
using System;
public class JaggedArrayForLoop
{
public static void Main()
{
var projectTasks = new []
{
new [] { "Design UI", "Implement Login" },
new [] { "Setup DB" },
new [] { "Test API", "Write Docs", "Deploy" }
};
// 外側のループ (行: i)
// projectTasks.Length は外側の配列の長さ (3)
for (int i = 0; i < projectTasks.Length; i++)
{
Console.WriteLine($"--- Project {i} (タスク数: {projectTasks[i].Length}) ---");
// 内側のループ (列: j)
// projectTasks[i].Length は「内側の配列」の長さ (2, 1, 3 と変化)
for (int j = 0; j < projectTasks[i].Length; j++)
{
Console.WriteLine($" Task: {projectTasks[i][j]}");
}
}
}
}
2. foreach ループによる反復処理
foreachループを使用すると、インデックスの管理が不要になり、より可読性が高くなります。
using System;
public class JaggedArrayForeachLoop
{
public static void Main()
{
var projectTasks = new []
{
new [] { "Design UI", "Implement Login" },
new [] { "Setup DB" },
new [] { "Test API", "Write Docs", "Deploy" }
};
// 外側のループ
// taskArray は string[] 型 (内側の配列)
foreach (var taskArray in projectTasks)
{
Console.WriteLine($"--- Project (タスク数: {taskArray.Length}) ---");
// 内側のループ
// task は string 型 (個々の要素)
foreach (var task in taskArray)
{
Console.WriteLine($" Task: {task}");
}
}
}
}
(forループとforeachループの出力結果は同じ):
--- Project 0 (タスク数: 2) ---
Task: Design UI
Task: Implement Login
--- Project 1 (タスク数: 1) ---
Task: Setup DB
--- Project 2 (タスク数: 3) ---
Task: Test API
Task: Write Docs
Task: Deploy
まとめ
ジャグ配列(int[][])は、各要素が異なる長さを持つことができる「配列の配列」です。
int[,](2次元): 常に長方形(行列)。アクセスは[i, j]。int[][](ジャグ): 行ごとに長さが異なってもよい。アクセスは[i][j]。
ジャグ配列は、行ごとに要素数が異なるデータを柔軟に扱う必要がある場合に非常に有効なデータ構造です。
