C#のジャグ配列とは?宣言・初期化・使い方と2次元配列との違いを初心者向けに解説

はじめに

C#で配列を学んでいると、「ジャグ配列」という言葉が出てくることがあります。

ジャグ配列は、簡単にいうと「配列の中に配列を入れる」データ構造です。通常の配列とは少し書き方が異なり、2次元配列とも似ているため、初心者のうちは混同しやすいポイントです。

たとえば、クラスごとに生徒数が違う点数データや、行ごとに項目数が異なる表のようなデータを扱いたい場合、ジャグ配列を使うと柔軟に管理できます。

この記事では、C#のジャグ配列について、宣言・初期化・使い方・2次元配列との違いを初心者向けにわかりやすく解説します。

1. C#のジャグ配列とは?

C#のジャグ配列は、配列の要素として別の配列を持つ配列です。

英語では「jagged array」と呼ばれます。「jagged」には「ギザギザした」「不揃いな」という意味があり、行ごとの要素数がそろっていなくてもよい配列であることを表しています。

1-1. ジャグ配列は「配列の中に配列を入れる」構造

通常の配列は、次のように1つの配列の中に値を並べます。

C#
int[] numbers = { 10, 20, 30 };

一方、ジャグ配列では、配列の中にさらに配列を入れます。

C#
int[][] jaggedArray = new int[][]
{
new int[] { 1, 2, 3 },
new int[] { 4, 5 },
new int[] { 6, 7, 8, 9 }
};

この例では、jaggedArrayという配列の中に、3つのint[]配列が入っています。

それぞれの行を見ると、要素数が異なっています。

C#
{ 1, 2, 3 }       // 要素数3
{ 4, 5 } // 要素数2
{ 6, 7, 8, 9 } // 要素数4

このように、行ごとに長さが違う配列を扱えるのがジャグ配列の大きな特徴です。

1-2. ジャグ配列が「配列の配列」と呼ばれる理由

ジャグ配列は「配列の配列」とも呼ばれます。

なぜなら、外側の配列の各要素が、さらに配列になっているからです。

C#
int[][] scores;

このint[][]という書き方は、int型の配列を要素に持つ配列という意味です。

分解して考えると、次のようになります。

C#
int[]     // int型の配列
int[][] // int型の配列を要素に持つ配列

つまり、int[][]は単なる数値の集まりではなく、int[]という配列を複数持つ構造です。

そのため、ジャグ配列は「配列の配列」と表現されます。

1-3. ジャグ配列でできることの具体例

ジャグ配列を使うと、行ごとに要素数が違うデータを自然に表現できます。

たとえば、クラスごとのテスト点数を管理する場合を考えてみましょう。

C#
int[][] classScores = new int[][]
{
new int[] { 80, 90, 75 },
new int[] { 88, 92 },
new int[] { 70, 85, 95, 100 }
};

この例では、クラスごとに生徒数が違います。

1組には3人、2組には2人、3組には4人いるようなデータを表すことができます。

また、曜日ごとの予定数が違う場合にも使えます。

C#
string[][] schedules = new string[][]
{
new string[] { "会議", "資料作成" },
new string[] { "打ち合わせ" },
new string[] { "コードレビュー", "テスト", "報告書作成" }
};

このように、データの数が行によって変わる場面では、ジャグ配列が便利です。

1-4. 初心者が混同しやすい2次元配列との違い

ジャグ配列と似たものに、2次元配列があります。

2次元配列は、行と列を持つ表のような配列です。

C#
int[,] array2D = new int[3, 4];

一方、ジャグ配列は配列の中に配列を入れる構造です。

C#
int[][] jaggedArray = new int[3][];

見た目は似ていますが、構造は異なります。

2次元配列は、すべての行で列数が同じです。

C#
int[,] array2D =
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};

この場合、すべての行が3列です。

一方、ジャグ配列では行ごとに要素数を変えられます。

C#
int[][] jaggedArray =
{
new int[] { 1, 2 },
new int[] { 3, 4, 5 },
new int[] { 6 }
};

この違いを理解すると、ジャグ配列と2次元配列を使い分けやすくなります。

2. C#でジャグ配列を宣言する方法

C#でジャグ配列を使うには、まず変数を宣言します。

ジャグ配列の宣言は、通常の配列よりも角かっこが多くなるため、最初は少し難しく見えるかもしれません。

しかし、意味を分解すれば理解しやすくなります。

2-1. ジャグ配列の基本的な宣言構文

ジャグ配列の基本構文は次のとおりです。

C#
データ型[][] 配列名;

たとえば、int型のジャグ配列なら次のように書きます。

C#
int[][] numbers;

これは、int[]を要素として持つ配列を宣言しているという意味です。

string型であれば、次のように書きます。

C#
string[][] words;

角かっこが2つ並んでいるため、2次元配列のように見えますが、ジャグ配列では[][]と分けて書きます。

2次元配列の場合は、次のように,を使います。

C#
int[,] array2D;

ジャグ配列と2次元配列では、宣言の時点で構文が異なります。

2-2. int型のジャグ配列を宣言する例

int型のジャグ配列を宣言する例を見てみましょう。

C#
int[][] scores;

この時点では、変数scoresを宣言しただけで、実際の配列はまだ作成されていません。

配列を作成するには、newを使います。

C#
int[][] scores = new int[3][];

このコードでは、外側の配列に3つの要素を持つジャグ配列を作成しています。

ただし、内側の配列はまだ作成されていません。

つまり、次のような状態です。

C#
scores[0] // まだnull
scores[1] // まだnull
scores[2] // まだnull

そのため、各行に配列を代入する必要があります。

C#
scores[0] = new int[] { 80, 90, 75 };
scores[1] = new int[] { 88, 92 };
scores[2] = new int[] { 70, 85, 95, 100 };

これで、int型のジャグ配列として使えるようになります。

2-3. string型のジャグ配列を宣言する例

string型のジャグ配列も、基本的な考え方は同じです。

C#
string[][] names = new string[2][];

このコードでは、外側に2つの要素を持つジャグ配列を作成しています。

次に、各行に文字列配列を代入します。

C#
names[0] = new string[] { "田中", "佐藤" };
names[1] = new string[] { "鈴木", "高橋", "伊藤" };

これで、行ごとに人数が違う名前一覧を表すことができます。

値を取り出す場合は、次のように書きます。

C#
Console.WriteLine(names[0][1]); // 佐藤
Console.WriteLine(names[1][2]); // 伊藤

names[0][1]は、0番目の配列の中にある1番目の要素を意味します。

2-4. 宣言時に注意するポイント

ジャグ配列を宣言するときは、次の点に注意しましょう。

まず、ジャグ配列は[][]で宣言します。

C#
int[][] jaggedArray;

2次元配列のように[,]とは書きません。

C#
int[,] array2D;

また、次のように外側の配列だけを作成した場合、内側の配列はまだ作成されていません。

C#
int[][] numbers = new int[3][];

この状態で、いきなり次のようにアクセスするとエラーになります。

C#
numbers[0][0] = 10;

numbers[0]がまだnullだからです。

正しくは、先に内側の配列を作成します。

C#
numbers[0] = new int[2];
numbers[0][0] = 10;

ジャグ配列では、外側の配列と内側の配列を別々に考えることが重要です。

3. C#でジャグ配列を初期化する方法

ジャグ配列の初期化には、いくつかの方法があります。

外側の配列だけを先に作る方法、各行の配列をあとから作る方法、宣言と同時に値を入れる方法などがあります。

用途に合わせて使い分けましょう。

3-1. 要素数を指定して初期化する方法

まずは、外側の配列の要素数を指定して初期化する方法です。

C#
int[][] numbers = new int[3][];

このコードでは、外側の配列に3つの要素を持つジャグ配列を作成しています。

ただし、この時点では内側の配列はまだ存在しません。

各行はnullです。

C#
Console.WriteLine(numbers.Length); // 3

numbers.Lengthは外側の配列の長さを表します。

つまり、この場合は行数が3であることを意味します。

しかし、次のように内側の配列へアクセスするとエラーになります。

C#
// numbers[0][0] = 10; // エラー

内側の配列を使うには、別途初期化が必要です。

3-2. 各行の配列をあとから作成する方法

外側の配列を作成したあと、各行の配列を個別に作ることができます。

C#
int[][] numbers = new int[3][];

numbers[0] = new int[2];
numbers[1] = new int[3];
numbers[2] = new int[4];

この例では、行ごとに要素数を変えています。

C#
numbers[0][0] = 10;
numbers[0][1] = 20;

numbers[1][0] = 30;
numbers[1][1] = 40;
numbers[1][2] = 50;

numbers[2][0] = 60;
numbers[2][1] = 70;
numbers[2][2] = 80;
numbers[2][3] = 90;

このように、ジャグ配列では各行を個別に作成できます。

行によって必要な要素数が違う場合に便利です。

3-3. 宣言と同時に値を入れて初期化する方法

ジャグ配列は、宣言と同時に値を入れて初期化することもできます。

C#
int[][] numbers = new int[][]
{
new int[] { 1, 2, 3 },
new int[] { 4, 5 },
new int[] { 6, 7, 8, 9 }
};

C#では、型を省略して次のように書くこともできます。

C#
int[][] numbers =
{
new int[] { 1, 2, 3 },
new int[] { 4, 5 },
new int[] { 6, 7, 8, 9 }
};

この書き方は、最初から値が決まっている場合に便利です。

string型でも同じように書けます。

C#
string[][] groups =
{
new string[] { "Aさん", "Bさん" },
new string[] { "Cさん" },
new string[] { "Dさん", "Eさん", "Fさん" }
};

3-4. 行ごとに要素数が違うジャグ配列の初期化例

ジャグ配列の特徴がよくわかる例として、行ごとに要素数が違う配列を作ってみましょう。

C#
int[][] data =
{
new int[] { 10, 20 },
new int[] { 30, 40, 50 },
new int[] { 60 },
new int[] { 70, 80, 90, 100 }
};

このジャグ配列では、各行の要素数が次のようになっています。

C#
data[0] // 要素数2
data[1] // 要素数3
data[2] // 要素数1
data[3] // 要素数4

各行の要素数は、Lengthで取得できます。

C#
Console.WriteLine(data[0].Length); // 2
Console.WriteLine(data[1].Length); // 3
Console.WriteLine(data[2].Length); // 1
Console.WriteLine(data[3].Length); // 4

2次元配列では、このように行ごとに列数を変えることはできません。

ジャグ配列なら、データの形に合わせて柔軟に配列を作れます。

4. C#のジャグ配列の使い方

ここからは、C#のジャグ配列を実際に使う方法を見ていきましょう。

要素へのアクセス、値の変更、for文やforeach文での処理、Lengthの使い方を順番に解説します。

4-1. ジャグ配列の要素にアクセスする方法

ジャグ配列の要素にアクセスするには、角かっこを2回使います。

C#
配列名[外側のインデックス][内側のインデックス]

たとえば、次のジャグ配列を見てください。

C#
int[][] numbers =
{
new int[] { 10, 20, 30 },
new int[] { 40, 50 },
new int[] { 60, 70, 80, 90 }
};

最初の行の1番目の要素を取得するには、次のように書きます。

C#
Console.WriteLine(numbers[0][0]); // 10

0番目の行にある2番目の要素を取得するには、次のように書きます。

C#
Console.WriteLine(numbers[0][1]); // 20

2番目の行の3番目の要素を取得するには、次のように書きます。

C#
Console.WriteLine(numbers[2][2]); // 80

C#の配列のインデックスは0から始まるため、最初の要素は[0]で指定します。

4-2. ジャグ配列の要素を変更する方法

ジャグ配列の要素は、通常の配列と同じように代入して変更できます。

C#
int[][] numbers =
{
new int[] { 10, 20, 30 },
new int[] { 40, 50 }
};

numbers[0][1] = 99;

Console.WriteLine(numbers[0][1]); // 99

この例では、numbers[0][1]の値を20から99に変更しています。

文字列のジャグ配列でも同じです。

C#
string[][] names =
{
new string[] { "田中", "佐藤" },
new string[] { "鈴木", "高橋" }
};

names[1][0] = "山田";

Console.WriteLine(names[1][0]); // 山田

ただし、存在しないインデックスを指定するとエラーになります。

C#
// Console.WriteLine(names[1][3]); // エラー

ジャグ配列では行ごとに要素数が違うため、アクセス前に各行の長さを確認することが大切です。

4-3. for文でジャグ配列を処理する方法

ジャグ配列をfor文で処理する場合、外側の配列と内側の配列をそれぞれループします。

C#
int[][] numbers =
{
new int[] { 10, 20, 30 },
new int[] { 40, 50 },
new int[] { 60, 70, 80, 90 }
};

for (int i = 0; i < numbers.Length; i++)
{
for (int j = 0; j < numbers[i].Length; j++)
{
Console.WriteLine(numbers[i][j]);
}
}

外側のfor文では、行数を表すnumbers.Lengthを使います。

内側のfor文では、各行の要素数を表すnumbers[i].Lengthを使います。

ここで重要なのは、内側のループ条件にnumbers[0].Lengthなど固定の長さを使わないことです。

ジャグ配列では行ごとに要素数が違う可能性があるため、必ずnumbers[i].Lengthを使いましょう。

4-4. foreach文でジャグ配列を処理する方法

foreach文を使うと、ジャグ配列をより簡潔に処理できます。

C#
int[][] numbers =
{
new int[] { 10, 20, 30 },
new int[] { 40, 50 },
new int[] { 60, 70, 80, 90 }
};

foreach (int[] row in numbers)
{
foreach (int value in row)
{
Console.WriteLine(value);
}
}

外側のforeach文では、各行の配列をrowとして取り出しています。

C#
foreach (int[] row in numbers)

内側のforeach文では、各行の要素を1つずつ取り出しています。

C#
foreach (int value in row)

インデックス番号が不要な場合は、for文よりforeach文の方が読みやすくなります。

一方、何行目・何列目かを使いたい場合は、for文の方が便利です。

4-5. Lengthを使って行数・列数を取得する方法

ジャグ配列で行数を取得するには、外側の配列に対してLengthを使います。

C#
int[][] numbers =
{
new int[] { 10, 20, 30 },
new int[] { 40, 50 },
new int[] { 60, 70, 80, 90 }
};

Console.WriteLine(numbers.Length); // 3

この場合、外側の配列には3つの配列が入っているため、行数は3です。

各行の要素数を取得するには、次のように書きます。

C#
Console.WriteLine(numbers[0].Length); // 3
Console.WriteLine(numbers[1].Length); // 2
Console.WriteLine(numbers[2].Length); // 4

ジャグ配列では、行ごとに要素数が違う可能性があります。

そのため、すべての行が同じ長さだと決めつけず、各行に対してLengthを確認することが重要です。

5. ジャグ配列と2次元配列の違い

ジャグ配列と2次元配列は、どちらも表のようなデータを扱えるため、見た目が似ています。

しかし、構文・構造・使い方には明確な違いがあります。

ここでは、初心者が混同しやすいポイントを整理します。

5-1. ジャグ配列と2次元配列の構文の違い

ジャグ配列は、次のように[][]で宣言します。

C#
int[][] jaggedArray;

一方、2次元配列は[,]で宣言します。

C#
int[,] array2D;

初期化の書き方も異なります。

ジャグ配列の場合は、各行を配列として作成します。

C#
int[][] jaggedArray =
{
new int[] { 1, 2, 3 },
new int[] { 4, 5 },
new int[] { 6, 7, 8, 9 }
};

2次元配列の場合は、行と列がそろった表のように書きます。

C#
int[,] array2D =
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};

ジャグ配列は「配列の配列」、2次元配列は「行と列を持つ1つの配列」と考えると理解しやすくなります。

5-2. 行ごとに要素数を変えられるかどうかの違い

ジャグ配列の大きな特徴は、行ごとに要素数を変えられることです。

C#
int[][] jaggedArray =
{
new int[] { 1, 2 },
new int[] { 3, 4, 5 },
new int[] { 6 }
};

このように、1行目は2個、2行目は3個、3行目は1個というデータを扱えます。

一方、2次元配列では、すべての行で列数が同じでなければなりません。

C#
int[,] array2D =
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};

2次元配列は、縦横がきれいにそろった表のようなデータに向いています。

逆に、行ごとにデータ数が違う場合はジャグ配列が向いています。

5-3. メモリ構造の違い

ジャグ配列と2次元配列は、メモリ上の構造も異なります。

ジャグ配列は、外側の配列があり、その各要素が別々の配列を参照しています。

C#
int[][] jaggedArray = new int[3][];

この場合、jaggedArray[0]jaggedArray[1]jaggedArray[2]は、それぞれ別の配列を参照できます。

一方、2次元配列は、行と列を持つ1つのまとまった配列です。

C#
int[,] array2D = new int[3, 4];

2次元配列では、3行4列のように形が固定されています。

ジャグ配列は行ごとに別々の配列を持つため柔軟ですが、その分、初期化やアクセス時に注意が必要です。

5-4. アクセス方法の違い

ジャグ配列では、要素にアクセスするときに角かっこを2回使います。

C#
jaggedArray[0][1]

これは、0番目の配列の中にある1番目の要素を意味します。

一方、2次元配列では、角かっこの中にカンマで区切ってインデックスを指定します。

C#
array2D[0, 1]

どちらも「0行目の1列目」のように見えますが、書き方が違います。

ジャグ配列は[行][列]、2次元配列は[行, 列]と覚えるとわかりやすいです。

5-5. 使い分けの判断基準

ジャグ配列と2次元配列は、データの形によって使い分けるのがおすすめです。

行ごとに要素数が違う場合は、ジャグ配列が向いています。

C#
int[][] classScores =
{
new int[] { 80, 90 },
new int[] { 75, 88, 92 },
new int[] { 60 }
};

クラスごとの人数が違う、曜日ごとの予定数が違う、カテゴリごとの商品数が違うといった場合です。

一方、行と列がきれいにそろっている場合は、2次元配列が向いています。

C#
int[,] board = new int[3, 3];

たとえば、マス目、座標、固定サイズの表、ゲーム盤面などです。

迷った場合は、次のように考えるとよいでしょう。

行ごとに長さが違うならジャグ配列、すべての行と列が同じ形なら2次元配列です。

6. ジャグ配列を使うメリット・デメリット

ジャグ配列は便利なデータ構造ですが、常に最適とは限りません。

メリットとデメリットを理解しておくことで、適切な場面で使えるようになります。

6-1. ジャグ配列のメリット

ジャグ配列の最大のメリットは、行ごとに要素数を変えられることです。

C#
int[][] data =
{
new int[] { 1, 2 },
new int[] { 3, 4, 5, 6 },
new int[] { 7 }
};

このように、不揃いなデータを無理なく表現できます。

また、各行が独立した配列なので、行単位で処理しやすい点もメリットです。

C#
int[] firstRow = data[0];

特定の行だけを別の配列として扱えるため、処理を分けたい場合に便利です。

さらに、必要な分だけ配列を作れるため、無駄な領域を減らせる場合があります。

たとえば、各行の要素数が大きく異なるデータを2次元配列で表すと、使わない空き領域が増えることがあります。

ジャグ配列なら、各行に必要な要素数だけを確保できます。

6-2. ジャグ配列のデメリット

ジャグ配列のデメリットは、初期化を忘れやすいことです。

C#
int[][] numbers = new int[3][];
numbers[0][0] = 10; // エラー

このコードでは、外側の配列だけを作成していて、numbers[0]の内側配列を作成していません。

そのため、NullReferenceExceptionが発生します。

また、行ごとに要素数が違うため、ループ処理で注意が必要です。

C#
for (int i = 0; i < numbers.Length; i++)
{
for (int j = 0; j < numbers[i].Length; j++)
{
Console.WriteLine(numbers[i][j]);
}
}

各行の長さを正しく使わないと、IndexOutOfRangeExceptionが発生する可能性があります。

さらに、複雑なデータをジャグ配列だけで表現しようとすると、コードの可読性が下がる場合があります。

6-3. ジャグ配列が向いているケース

ジャグ配列は、行ごとにデータ数が異なるケースに向いています。

たとえば、次のような場面です。

クラスごとの生徒の点数を管理する場合。

C#
int[][] scores =
{
new int[] { 80, 90, 75 },
new int[] { 88, 92 },
new int[] { 70, 85, 95, 100 }
};

カテゴリごとの商品IDを管理する場合。

C#
int[][] productIds =
{
new int[] { 101, 102 },
new int[] { 201, 202, 203 },
new int[] { 301 }
};

日ごとの予定を管理する場合。

C#
string[][] schedules =
{
new string[] { "会議", "資料作成" },
new string[] { "面談" },
new string[] { "レビュー", "テスト", "報告" }
};

このように、データ数が不揃いな場合にジャグ配列は便利です。

6-4. 2次元配列を使った方がよいケース

2次元配列を使った方がよいのは、行数と列数が固定されている場合です。

たとえば、3×3のゲーム盤面を表す場合です。

C#
int[,] board = new int[3, 3];

また、縦横がそろった表形式のデータにも向いています。

C#
int[,] matrix =
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};

すべての行に同じ数の列があるなら、2次元配列の方がわかりやすい場合があります。

ジャグ配列は柔軟ですが、形が固定されているデータに使うと、かえって意図がわかりにくくなることもあります。

7. C#のジャグ配列でよくあるエラーと対処法

ジャグ配列でよく発生するエラーには、NullReferenceExceptionIndexOutOfRangeExceptionがあります。

どちらも初心者がつまずきやすいエラーです。

原因と対処法を理解しておきましょう。

7-1. NullReferenceExceptionが発生する原因

NullReferenceExceptionは、nullのものにアクセスしようとしたときに発生します。

ジャグ配列では、外側の配列だけを作成して、内側の配列を作成していない場合によく発生します。

C#
int[][] numbers = new int[3][];

numbers[0][0] = 10; // NullReferenceException

このコードでは、numbersという外側の配列は作成されています。

しかし、numbers[0]にはまだ配列が入っていません。

そのため、numbers[0][0]にアクセスしようとするとエラーになります。

正しくは、先に内側の配列を作成します。

C#
int[][] numbers = new int[3][];

numbers[0] = new int[2];
numbers[0][0] = 10;

ジャグ配列では、外側の配列と内側の配列をそれぞれ初期化する必要があります。

7-2. IndexOutOfRangeExceptionが発生する原因

IndexOutOfRangeExceptionは、存在しないインデックスにアクセスしたときに発生します。

たとえば、次のコードを見てください。

C#
int[][] numbers =
{
new int[] { 10, 20 },
new int[] { 30, 40, 50 }
};

Console.WriteLine(numbers[0][2]); // IndexOutOfRangeException

numbers[0]には、1020の2つしか要素がありません。

インデックスは0から始まるため、有効なインデックスは01です。

numbers[0][2]は存在しないため、エラーになります。

ジャグ配列では、行ごとに要素数が違うため、各行のLengthを確認してからアクセスすることが大切です。

C#
if (numbers[0].Length > 2)
{
Console.WriteLine(numbers[0][2]);
}

7-3. 各行の配列を初期化し忘れた場合の対処法

各行の配列を初期化し忘れた場合は、newを使って内側の配列を作成します。

悪い例は次のとおりです。

C#
int[][] scores = new int[2][];

scores[0][0] = 80; // エラー

正しい例は次のとおりです。

C#
int[][] scores = new int[2][];

scores[0] = new int[3];
scores[1] = new int[2];

scores[0][0] = 80;
scores[0][1] = 90;
scores[0][2] = 75;

scores[1][0] = 88;
scores[1][1] = 92;

また、最初から値が決まっている場合は、宣言と同時に初期化するとミスを減らせます。

C#
int[][] scores =
{
new int[] { 80, 90, 75 },
new int[] { 88, 92 }
};

初期化漏れを防ぐには、外側の配列だけでなく、内側の配列も作成されているかを意識しましょう。

7-4. Lengthの使い方を間違えた場合の対処法

ジャグ配列では、Lengthの使い方にも注意が必要です。

外側の配列の長さを取得する場合は、次のように書きます。

C#
numbers.Length

各行の長さを取得する場合は、次のように書きます。

C#
numbers[i].Length

よくある間違いは、すべての行が同じ長さだと思って、内側のループで固定の長さを使ってしまうことです。

C#
for (int i = 0; i < numbers.Length; i++)
{
for (int j = 0; j < numbers[0].Length; j++)
{
Console.WriteLine(numbers[i][j]);
}
}

このコードは、すべての行がnumbers[0]と同じ長さである場合にしか安全ではありません。

ジャグ配列では行ごとに要素数が違うため、次のように書くのが基本です。

C#
for (int i = 0; i < numbers.Length; i++)
{
for (int j = 0; j < numbers[i].Length; j++)
{
Console.WriteLine(numbers[i][j]);
}
}

内側の配列の長さは、必ず現在の行に対して取得しましょう。

8. ジャグ配列の実践的なサンプルコード

ここでは、C#のジャグ配列を使った実践的なサンプルコードを紹介します。

実際の用途に近い例を見ることで、ジャグ配列の使いどころが理解しやすくなります。

8-1. 点数一覧をジャグ配列で管理する例

クラスごとに生徒の点数を管理する例です。

クラスによって生徒数が違う場合、ジャグ配列を使うと自然に表現できます。

C#
int[][] scores =
{
new int[] { 80, 90, 75 },
new int[] { 88, 92 },
new int[] { 70, 85, 95, 100 }
};

for (int i = 0; i < scores.Length; i++)
{
Console.WriteLine($"{i + 1}組の点数:");

for (int j = 0; j < scores[i].Length; j++)
{
Console.WriteLine($"{j + 1}人目: {scores[i][j]}点");
}
}

実行結果のイメージは次のようになります。

C#
1組の点数:
1人目: 80
2人目: 90
3人目: 75
2組の点数:
1人目: 88
2人目: 92
3組の点数:
1人目: 70
2人目: 85
3人目: 95
4人目: 100

行ごとに人数が違っても、scores[i].Lengthを使えば安全に処理できます。

8-2. クラスごとに人数が違うデータを扱う例

次は、クラスごとに生徒名を管理する例です。

C#
string[][] students =
{
new string[] { "田中", "佐藤", "鈴木" },
new string[] { "高橋", "伊藤" },
new string[] { "山田", "中村", "小林", "加藤" }
};

for (int i = 0; i < students.Length; i++)
{
Console.WriteLine($"{i + 1}組:");

foreach (string student in students[i])
{
Console.WriteLine(student);
}
}

ジャグ配列を使うことで、クラスごとの人数が違っても無理なく管理できます。

2次元配列で同じことをしようとすると、人数が少ないクラスには空の要素を入れる必要が出てくる場合があります。

ジャグ配列なら、必要な人数分だけ配列を作ればよいため、データ構造が自然になります。

8-3. 文字列データをジャグ配列で管理する例

文字列のカテゴリデータをジャグ配列で管理する例です。

C#
string[][] categories =
{
new string[] { "C#", "Java", "Python" },
new string[] { "HTML", "CSS" },
new string[] { "SQL", "NoSQL", "Redis", "MongoDB" }
};

string[] categoryNames = { "プログラミング言語", "Web技術", "データベース" };

for (int i = 0; i < categories.Length; i++)
{
Console.WriteLine(categoryNames[i]);

for (int j = 0; j < categories[i].Length; j++)
{
Console.WriteLine($"- {categories[i][j]}");
}
}

このように、カテゴリごとに項目数が異なるデータにもジャグ配列は使えます。

出力時にカテゴリ名の配列と組み合わせることで、見やすい一覧を作ることもできます。

8-4. ジャグ配列の全要素を合計する例

数値のジャグ配列に入っているすべての要素を合計する例です。

C#
int[][] numbers =
{
new int[] { 10, 20, 30 },
new int[] { 40, 50 },
new int[] { 60, 70, 80, 90 }
};

int total = 0;

for (int i = 0; i < numbers.Length; i++)
{
for (int j = 0; j < numbers[i].Length; j++)
{
total += numbers[i][j];
}
}

Console.WriteLine($"合計: {total}");

foreach文を使うと、よりシンプルに書けます。

C#
int total = 0;

foreach (int[] row in numbers)
{
foreach (int value in row)
{
total += value;
}
}

Console.WriteLine($"合計: {total}");

インデックスが不要な場合は、foreach文の方が読みやすくなります。

一方、何行目・何列目かを使いたい場合は、for文を使うとよいでしょう。

9. ジャグ配列を使うときの注意点

ジャグ配列は便利ですが、使い方を間違えるとエラーや読みにくいコードの原因になります。

ここでは、ジャグ配列を使うときに意識したい注意点を紹介します。

9-1. 各行の要素数が異なることを前提に処理する

ジャグ配列では、各行の要素数が異なる可能性があります。

そのため、すべての行が同じ長さであると決めつけないようにしましょう。

悪い例は次のとおりです。

C#
for (int i = 0; i < data.Length; i++)
{
for (int j = 0; j < data[0].Length; j++)
{
Console.WriteLine(data[i][j]);
}
}

このコードでは、すべての行がdata[0]と同じ長さであることを前提にしています。

行ごとに要素数が違う場合は、エラーになる可能性があります。

正しくは、現在の行の長さを使います。

C#
for (int i = 0; i < data.Length; i++)
{
for (int j = 0; j < data[i].Length; j++)
{
Console.WriteLine(data[i][j]);
}
}

ジャグ配列を処理するときは、常にdata[i].Lengthを使う意識を持ちましょう。

9-2. 初期化漏れに注意する

ジャグ配列では、外側の配列を作成しただけでは内側の配列は使えません。

C#
int[][] data = new int[3][];

この状態では、data[0]data[1]data[2]はまだnullです。

各行を使う前に、内側の配列を作成する必要があります。

C#
data[0] = new int[2];
data[1] = new int[3];
data[2] = new int[1];

初期化漏れが心配な場合は、宣言と同時に値を入れる方法を使うと安全です。

C#
int[][] data =
{
new int[] { 1, 2 },
new int[] { 3, 4, 5 },
new int[] { 6 }
};

9-3. 可読性を意識して使う

ジャグ配列は便利ですが、データ構造が複雑になるとコードが読みにくくなることがあります。

たとえば、次のようなコードは意味が伝わりにくい場合があります。

C#
int[][] data =
{
new int[] { 1, 2, 3 },
new int[] { 4, 5 },
new int[] { 6, 7, 8, 9 }
};

この配列が何を表しているのか、変数名やコメントでわかりやすくすることが大切です。

C#
int[][] classScores =
{
new int[] { 80, 90, 75 },
new int[] { 88, 92 },
new int[] { 70, 85, 95, 100 }
};

dataのような抽象的な名前より、classScoresのように意味がわかる名前を付けると、コードが読みやすくなります。

また、複雑な処理を行う場合は、メソッドに分けることも検討しましょう。

9-4. 複雑なデータ構造ではListやクラスも検討する

ジャグ配列は、行ごとに要素数が違うデータを扱うのに便利です。

しかし、データの追加や削除が多い場合は、List<T>を使った方が扱いやすいことがあります。

たとえば、次のようにリストのリストを使えます。

C#
List<List<int>> scores = new List<List<int>>
{
new List<int> { 80, 90, 75 },
new List<int> { 88, 92 },
new List<int> { 70, 85, 95, 100 }
};

List<T>は要素の追加や削除がしやすいため、データ数が変化する場合に向いています。

C#
scores[0].Add(85);

また、データに名前や属性が増えてきた場合は、クラスを作った方がわかりやすくなります。

C#
class Student
{
public string Name { get; set; }
public int Score { get; set; }
}

単純な数値や文字列のまとまりならジャグ配列で十分ですが、複雑なデータを扱う場合は、Listやクラスも選択肢に入れましょう。

10. C#のジャグ配列に関するよくある質問

最後に、C#のジャグ配列について初心者が疑問に思いやすい内容をQ&A形式で解説します。

10-1. ジャグ配列と多次元配列は同じですか?

ジャグ配列と多次元配列は同じではありません。

ジャグ配列は、配列の中に配列を入れる「配列の配列」です。

C#
int[][] jaggedArray;

多次元配列は、複数の次元を持つ1つの配列です。

C#
int[,] array2D;

どちらも表のようなデータを扱えますが、構造と書き方が異なります。

ジャグ配列は行ごとに要素数を変えられますが、2次元配列では基本的に行と列の形が固定されます。

10-2. ジャグ配列は何次元配列ですか?

ジャグ配列は、厳密には多次元配列ではなく、配列の要素として配列を持つ構造です。

ただし、見た目や使い方としては2次元的なデータを扱うことができます。

C#
int[][] numbers =
{
new int[] { 1, 2 },
new int[] { 3, 4, 5 }
};

この例では、numbers[0][1]のように2つのインデックスを使って値にアクセスします。

そのため、初心者向けには「2次元配列に似た使い方ができる配列」と考えると理解しやすいです。

ただし、C#の構文としてはint[,]のような多次元配列とは別物です。

10-3. ジャグ配列の要素数はあとから変更できますか?

配列そのものの長さは、作成後に変更できません。

たとえば、次のように作成した配列の長さは固定です。

C#
int[] row = new int[3];

このrowの要素数は3で固定されます。

ただし、ジャグ配列では、各行に別の配列を代入し直すことはできます。

C#
int[][] numbers = new int[2][];

numbers[0] = new int[] { 1, 2 };
numbers[0] = new int[] { 1, 2, 3, 4 };

このように、行の配列を別の配列に置き換えることで、結果的に要素数を変えたように扱えます。

ただし、頻繁に要素数を変更したい場合は、配列よりもList<T>を使う方が便利です。

10-4. Listとジャグ配列はどちらを使うべきですか?

データ数が固定されている場合は、ジャグ配列で問題ありません。

C#
int[][] scores =
{
new int[] { 80, 90 },
new int[] { 75, 88, 92 }
};

一方、あとから要素を追加したり削除したりする場合は、List<T>の方が扱いやすいです。

C#
List<List<int>> scores = new List<List<int>>
{
new List<int> { 80, 90 },
new List<int> { 75, 88, 92 }
};

scores[0].Add(100);

配列は長さが固定されるため、データの数が変化しやすい場合には向いていません。

学習目的や固定データにはジャグ配列、実際のアプリ開発で柔軟にデータを扱いたい場合にはListを検討するとよいでしょう。

10-5. 初心者はジャグ配列と2次元配列のどちらを先に覚えるべきですか?

初心者は、まず通常の1次元配列を理解し、その次に2次元配列とジャグ配列の違いを学ぶのがおすすめです。

順番としては、次の流れがわかりやすいです。

C#
int[] numbers;     // 1次元配列
int[,] array2D; // 2次元配列
int[][] jagged; // ジャグ配列

2次元配列は、表のような形で理解しやすいです。

一方、ジャグ配列は「配列の中に配列が入る」という考え方が必要です。

そのため、通常の配列に慣れてからジャグ配列を学ぶと理解しやすくなります。

ただし、行ごとに要素数が違うデータを扱う場面では、ジャグ配列の方が実用的です。

まとめ

C#のジャグ配列は、配列の中に配列を入れる「配列の配列」です。

基本的な宣言は、次のように書きます。

C#
int[][] jaggedArray;

ジャグ配列では、行ごとに要素数を変えられます。

C#
int[][] numbers =
{
new int[] { 1, 2 },
new int[] { 3, 4, 5 },
new int[] { 6 }
};

2次元配列との主な違いは、構文とデータ構造です。

ジャグ配列は[][]を使い、要素へのアクセスは次のように書きます。

C#
numbers[0][1]

2次元配列は[,]を使い、要素へのアクセスは次のように書きます。

C#
array2D[0, 1]

ジャグ配列は、クラスごとの人数が違うデータ、カテゴリごとの項目数が違うデータ、曜日ごとの予定数が違うデータなど、不揃いなデータを扱うときに便利です。

一方、行と列がきれいにそろった表や固定サイズのマス目を扱う場合は、2次元配列の方が向いています。

ジャグ配列を使うときは、内側の配列の初期化漏れや、Lengthの使い方に注意しましょう。

特に、ループ処理では各行の要素数が異なることを前提に、次のように書くのが基本です。

C#
for (int i = 0; i < numbers.Length; i++)
{
for (int j = 0; j < numbers[i].Length; j++)
{
Console.WriteLine(numbers[i][j]);
}
}

C#のジャグ配列は、最初は少し複雑に見えますが、「外側の配列」と「内側の配列」を分けて考えると理解しやすくなります。2次元配列との違いを押さえながら、データの形に合わせて適切に使い分けましょう。