.NETでは、単純な配列(1次元配列)だけでなく、矩形の構造を持つ多次元配列(矩形配列)と、配列が入れ子になった構造を持つジャグ配列(多段配列・配列の配列)を扱うことができます。

多次元配列とジャグ配列

多次元配列は通常の配列(1次元配列)の次元を拡張したもので、マトリックスやグリッド、テーブルの様な矩形の構造を持ったデータ構造であることから、矩形配列とも呼ばれます。 (§.多次元配列 (矩形配列))

一方、ジャグ配列は配列を格納することができる配列(配列の配列)であり、その事から多段配列とも呼ばれます。 ジャグ配列は、常に矩形である多次元配列とは異なり構造がギザギザ(jagged)になることが、その名前の由来となっています。 (§.ジャグ配列 (多段配列))

ジャグ配列は多次元配列とは異なり、異なる要素数の配列を格納することができます。 例えば、2次元配列が持ちうる要素数は1次元目の長さがn、2次元目の長さがm個とすると計n×m個となり、常に次元ごとの長さの積が全要素数となります。 一方、2段のジャグ配列ではa個の配列+b個の配列+c個の配列…とジャグ配列内に格納されている配列の要素数の和となります。

配列と2次元配列・2段のジャグ配列
// (通常の/1次元の)配列
int[] array = { 0, 1, 2, 3 };

// 3×4個の要素を持つ2次元配列
int[,] matrix = {
  {0, 1, 2, 3},
  {4, 5, 6, 7},
  {8, 9, 10, 11},
};

// 1段目の長さが3、2段目の長さが各々3, 2, 4の2段のジャグ配列
int[][] jagged = {
  new int[] {0, 1, 2},
  new int[] {3, 4},
  new int[] {5, 6, 7, 8},
};
配列と2次元配列・2段のジャグ配列
' (通常の/1次元の)配列
Dim array As Integer() = { 0, 1, 2, 3 }

' 3×4個の要素を持つ2次元配列
Dim matrix As Integer(,) = { _
  {0, 1, 2, 3}, _
  {4, 5, 6, 7}, _
  {8, 9, 10, 11} _
}

' 1段目の長さが3、2段目の長さが各々3, 2, 4の2段のジャグ配列
Dim jagged()() As Integer = { _
  New Integer() {0, 1, 2}, _
  New Integer() {3, 4}, _
  New Integer() {5, 6, 7, 8} _
}

上記のコードで表現される配列・2次元配列・2段のジャグ配列を図式化すると次のようになります。

配列のイメージ
0 1 2 3
2次元配列のイメージ
0 1 2 3
4 5 6 7
8 9 10 11
2段のジャグ配列のイメージ
0 1 2
3 4
5 6 7 8

多次元配列は行列の演算や表計算のセル表現のなどの用途で良く使われますが、ジャグ配列の用途がイメージしづらければ、カレンダーを想像するとよいでしょう。 カレンダーでは月ごとに日数が異なりますが、これを表現するのにジャグ配列が使えます。 全12ヶ月をジャグ配列の1段目、各月の日数に応じたデータをジャグ配列の2段目で表現できます。

2段のジャグ配列で表現したカレンダー
1月 1月1日1月2日1月28日1月29日1月30日1月31日
2月 2月1日2月2日2月28日
3月 3月1日3月2日3月28日3月29日3月30日3月31日
4月 4月1日4月2日4月28日4月29日4月30日
5月 5月1日5月2日5月28日5月29日5月30日5月31日
:
:

多次元配列 (矩形配列)

宣言・作成・要素の参照

2次元配列を宣言・作成し要素を参照する例について見てみます。 次の例では1次元目の長さが3、2次元目の長さが4の計3×4個の要素を持つ2次元配列を作成しています。

2次元配列の作成・2次元配列要素の参照
using System;

class Sample {
  static void Main()
  {
    // 3×4個の要素を持つ2次元配列を作成
    int[,] matrix = new int[3, 4];

    // 1次元目のインデックスが0、2次元目のインデックスが0の要素(最初の要素)に値を設定
    matrix[0, 0] = 0;

    // 1次元目のインデックスが2、2次元目のインデックスが3の要素(最後の要素)に値を設定
    matrix[2, 3] = 11;
  }
}
2次元配列の作成・2次元配列要素の参照
Imports System

Class Sample
  Shared Sub Main()
    ' 3×4個の要素を持つ2次元配列を作成
    Dim matrix(2, 3) As Integer

    ' 1次元目のインデックスが0、2次元目のインデックスが0の要素(最初の要素)に値を設定
    matrix(0, 0) = 0

    ' 1次元目のインデックスが2、2次元目のインデックスが3の要素(最後の要素)に値を設定
    matrix(2, 3) = 11
  End Sub
End Class

2次元配列を宣言する場合は、次元毎に要素数(またはインデックスの最大値)をカンマで区切って記述します。 2次元配列内の各要素を参照する場合も同様にインデックスをカンマで区切って記述します。

上記のコードで作成される2次元配列を図式化すると次のようになります。 1次元目を縦方向、2次元目を横方向で表しています。

長さが3×4の2次元配列のイメージ
matrix[0, 0] matrix[0, 1] matrix[0, 2] matrix[0, 3]
matrix[1, 0] matrix[1, 1] matrix[1, 2] matrix[1, 3]
matrix[2, 0] matrix[2, 1] matrix[2, 2] matrix[2, 3]

初期値を与えて多次元配列を初期化する方法、多次元配列における配列初期化子については§.初期化 (配列初期化子)で解説します。

3次元以上の配列を宣言・作成する場合も同様に、1次元目, 2次元目, 3次元目, … と次元の数だけカンマで区切って長さを指定します。

3次元配列の作成・3次元配列要素の参照
using System;

class Sample {
  static void Main()
  {
    // 4×2×3個の要素を持つ3次元配列
    int[,,] cube = new int[4, 2, 3];

    cube[0, 1, 2] = 5;
  }
}
3次元配列の作成・3次元配列要素の参照
Imports System

Class Sample
  Shared Sub Main()
    ' 4×2×3個の要素を持つ3次元配列を作成
    Dim cube(3, 1, 2) As Integer

    cube(0, 1, 2) = 5
  End Sub
End Class
4次元配列の作成・4次元配列要素の参照
using System;

class Sample {
  static void Main()
  {
    // 2×2×2×2個の要素を持つ4次元配列を作成
    int[,,,] tesseract = new int[2, 2, 2, 2];

    tesseract[1, 1, 0, 1] = 16;
  }
}
4次元配列の作成・4次元配列要素の参照
Imports System

Class Sample
  Shared Sub Main()
    ' 2×2×2×2個の要素を持つ4次元配列を作成
    Dim tesseract(1, 1, 1, 1) As Integer

    tesseract(1, 1, 0, 1) = 16
  End Sub
End Class

宣言されているものと異なる次元の配列を代入しようとするとコンパイル時にエラーとなります。

次元の異なる配列を代入しようとした場合、コンパイルエラーとなる
using System;

class Sample {
  static void Main()
  {
    // 3次元配列
    int[,,] cube = new int[4, 2, 3];

    // 2次元配列を格納する変数
    int[,] matrix;

    // sample.cs(13,14): error CS0029: 型 'int[*,*,*]' を型 'int[*,*]' に暗黙的に変換できません。
    matrix = cube;
  }
}
次元の異なる配列を代入しようとした場合、コンパイルエラーとなる
Imports System

Class Sample
  Shared Sub Main()
    ' 3次元配列
    Dim cube(3, 1, 2) As Integer

    ' 2次元配列を格納する変数
    Dim matrix(,) As Integer

    ' E:\sample.vb(12) : error BC30414: 配列型の次元数が異なるため、型 'Integer の 3次元配列' の値を 'Integer の 2 次元配列' に変換できません。
    matrix = cube
  End Sub
End Class

初期化 (配列初期化子)

多次元配列の場合でも配列初期化子を使って初期化することができます。 配列初期化子を使って初期化する場合は、1つの次元を数列とみなして1次元配列と同様の記述で表現し、それらを入れ子にすることで複数の次元を表現します。

次の例では、1次元目の長さが3、2次元目の長さが4の計3×4個の要素を持つ2次元配列を作成すると同時に初期化を行っています。

配列初期化子を使って2次元配列を初期化する
using System;

class Sample {
  static void Main()
  {
    // 3×4個の要素を持つ2次元配列を作成
    int[,] matrix = {
      {0, 1, 2, 3},
      {4, 5, 6, 7},
      {8, 9, 10, 11},
    };

    Console.WriteLine("matrix[0, 0] = {0}", matrix[0, 0]);
    Console.WriteLine("matrix[0, 1] = {0}", matrix[0, 1]);
    Console.WriteLine("matrix[1, 0] = {0}", matrix[1, 0]);
    Console.WriteLine("matrix[2, 3] = {0}", matrix[2, 3]);
  }
}
配列初期化子を使って2次元配列を初期化する
Imports System

Class Sample
  Shared Sub Main()
    ' 3×4個の要素を持つ2次元配列を作成
    Dim matrix As Integer(,) = { _
      {0, 1, 2, 3}, _
      {4, 5, 6, 7}, _
      {8, 9, 10, 11} _
    }

    Console.WriteLine("matrix(0, 0) = {0}", matrix(0, 0))
    Console.WriteLine("matrix(0, 1) = {0}", matrix(0, 1))
    Console.WriteLine("matrix(1, 0) = {0}", matrix(1, 0))
    Console.WriteLine("matrix(2, 3) = {0}", matrix(2, 3))
  End Sub
End Class
実行結果
matrix[0, 0] = 0
matrix[0, 1] = 1
matrix[1, 0] = 4
matrix[2, 3] = 11

このコードで作成・初期化される2次元配列を図式化すると次のようになります。

初期化後に2次元配列へ格納される値のイメージ
matrix[m, n] [m, 0] [m, 1] [m, 2] [m, 3]
[0, n] 0 1 2 3
[1, n] 4 5 6 7
[2, n] 8 9 10 11

3次元以上の多次元配列も同様にして初期化することができます。 2次元目は入れ子の2段目、3次元目は入れ子の3段目と、より高い次元の数列を入れ子の内側に記述します。 次元が高くなる分、記述も複雑になるので注意してください。

配列初期化子を使って3次元配列を初期化する
using System;

class Sample {
  static void Main()
  {
    // 4×2×3個の要素を持つ3次元配列
    int[,,] cube = {
      {  { 0,  1,  2},  { 3,  4,  5}  },
      {  { 6,  7,  8},  { 9, 10, 11}  },
      {  {12, 13, 14},  {15, 16, 17}  },
      {  {18, 19, 20},  {21, 22, 23}  },
    };

    Console.WriteLine("cube[0, 0, 0] = {0}", cube[0, 0, 0]);
    Console.WriteLine("cube[0, 0, 1] = {0}", cube[0, 0, 1]);
    Console.WriteLine("cube[0, 1, 0] = {0}", cube[0, 1, 0]);
    Console.WriteLine("cube[1, 0, 0] = {0}", cube[1, 0, 0]);
    Console.WriteLine("cube[3, 1, 2] = {0}", cube[3, 1, 2]);
  }
}
配列初期化子を使って3次元配列を初期化する
Imports System

Class Sample
  Shared Sub Main()
    ' 4×2×3個の要素を持つ3次元配列
    Dim cube As Integer(,,) = { _
      {  { 0,  1,  2},  { 3,  4,  5}  }, _
      {  { 6,  7,  8},  { 9, 10, 11}  }, _
      {  {12, 13, 14},  {15, 16, 17}  }, _
      {  {18, 19, 20},  {21, 22, 23}  } _
    }

    Console.WriteLine("cube(0, 0, 0) = {0}", cube(0, 0, 0))
    Console.WriteLine("cube(0, 0, 1) = {0}", cube(0, 0, 1))
    Console.WriteLine("cube(0, 1, 0) = {0}", cube(0, 1, 0))
    Console.WriteLine("cube(1, 0, 0) = {0}", cube(1, 0, 0))
    Console.WriteLine("cube(3, 1, 2) = {0}", cube(3, 1, 2))
  End Sub
End Class
実行結果
cube[0, 0, 0] = 0
cube[0, 0, 1] = 1
cube[0, 1, 0] = 3
cube[1, 0, 0] = 6
cube[3, 1, 2] = 23
配列初期化子を使って4次元配列を初期化する
using System;

class Sample {
  static void Main()
  {
    // 2×2×2×2個の要素を持つ4次元配列
    int[,,,] tesseract = {
      {  {  {0, 1},  { 2,  3}  },  {  { 4,  5},  { 6,  7}  }  },
      {  {  {8, 9},  {10, 11}  },  {  {12, 13},  {14, 15}  }  },
    };

    Console.WriteLine("tesseract[0, 0, 0, 0] = {0}", tesseract[0, 0, 0, 0]);
    Console.WriteLine("tesseract[0, 0, 0, 1] = {0}", tesseract[0, 0, 0, 1]);
    Console.WriteLine("tesseract[0, 0, 1, 0] = {0}", tesseract[0, 0, 1, 0]);
    Console.WriteLine("tesseract[0, 1, 0, 0] = {0}", tesseract[0, 1, 0, 0]);
    Console.WriteLine("tesseract[1, 0, 0, 0] = {0}", tesseract[1, 0, 0, 0]);
    Console.WriteLine("tesseract[1, 1, 1, 1] = {0}", tesseract[1, 1, 1, 1]);
  }
}
配列初期化子を使って4次元配列を初期化する
Imports System

Class Sample
  Shared Sub Main()
    ' 2×2×2×2個の要素を持つ4次元配列
    Dim tesseract As Integer(,,,) = { _
      {  {  {0, 1},  { 2,  3}  },  {  { 4,  5},  { 6,  7}  }  }, _
      {  {  {8, 9},  {10, 11}  },  {  {12, 13},  {14, 15}  }  } _
    }

    Console.WriteLine("tesseract(0, 0, 0, 0) = {0}", tesseract(0, 0, 0, 0))
    Console.WriteLine("tesseract(0, 0, 0, 1) = {0}", tesseract(0, 0, 0, 1))
    Console.WriteLine("tesseract(0, 0, 1, 0) = {0}", tesseract(0, 0, 1, 0))
    Console.WriteLine("tesseract(0, 1, 0, 0) = {0}", tesseract(0, 1, 0, 0))
    Console.WriteLine("tesseract(1, 0, 0, 0) = {0}", tesseract(1, 0, 0, 0))
    Console.WriteLine("tesseract(1, 1, 1, 1) = {0}", tesseract(1, 1, 1, 1))
  End Sub
End Class
実行結果
tesseract[0, 0, 0, 0] = 0
tesseract[0, 0, 0, 1] = 1
tesseract[0, 0, 1, 0] = 2
tesseract[0, 1, 0, 0] = 4
tesseract[1, 0, 0, 0] = 8
tesseract[1, 1, 1, 1] = 15

次元ごとの長さ・次元数・要素数の取得 (Length/GetLength/Rank)

1次元配列でLengthプロパティを参照すると要素数が取得できます。 一方、多次元配列でLengthプロパティを参照した場合、返される値は多次元配列の全要素数となります。 つまり、3×4個の要素を持つ2次元配列の場合、Lengthプロパティは12を返します。

次元毎の長さを取得したい場合は、GetLengthメソッドを呼び出します。 取得したい次元の番号を指定してGetLengthメソッドを呼び出すことで、多次元配列におけるその次元の長さが返されます。

GetLengthメソッドでは、最初の次元は0、その次の次元は1として扱われるため、例えば3次元配列の場合は0~2の値を次元の番号として指定します。 1次元配列に対してもGetLengthメソッドを呼び出すことはできます。 この場合、返される結果はLengthプロパティと同じです。

また、Rankプロパティを参照することで、多次元配列の次元数(次元の高さ)を取得できます。 1次元配列では1、2次元配列では2が返されます。

多次元配列の全要素数・次元数・次元ごとの長さを取得する
using System;

class Sample {
  static void Main()
  {
    // 5個の要素を持つ1次元配列
    int[] arr = new int[5];

    Console.WriteLine("arr.Length = {0}", arr.Length);
    Console.WriteLine("arr.Rank = {0}", arr.Rank);
    Console.WriteLine("arr = {0}", arr.GetLength(0));
    Console.WriteLine();

    // 3×4個の要素を持つ2次元配列
    int[,] matrix = new int[3, 4];

    Console.WriteLine("matrix.Length = {0}", matrix.Length);
    Console.WriteLine("matrix.Rank = {0}", matrix.Rank);
    Console.WriteLine("matrix = {0}×{1}", matrix.GetLength(0), matrix.GetLength(1));
    Console.WriteLine();

    // 4×2×3個の要素を持つ3次元配列
    int[,,] cube = new int[4, 2, 3];

    Console.WriteLine("cube.Length = {0}", cube.Length);
    Console.WriteLine("cube.Rank = {0}", cube.Rank);
    Console.WriteLine("cube = {0}×{1}×{2}", cube.GetLength(0), cube.GetLength(1), cube.GetLength(2));
    Console.WriteLine();

    // 2×2×2×2個の要素を持つ4次元配列
    int[,,,] tesseract = new int[2, 2, 2, 2];

    Console.WriteLine("tesseract.Length = {0}", tesseract.Length);
    Console.WriteLine("tesseract.Rank = {0}", tesseract.Rank);
    Console.WriteLine("tesseract = {0}×{1}×{2}×{3}", tesseract.GetLength(0), tesseract.GetLength(1), tesseract.GetLength(2), tesseract.GetLength(3));
  }
}
多次元配列の全要素数・次元数・次元ごとの長さを取得する
Imports System

Class Sample
  Shared Sub Main()
    ' 5個の要素を持つ1次元配列
    Dim arr(4) As Integer

    Console.WriteLine("arr.Length = {0}", arr.Length)
    Console.WriteLine("arr.Rank = {0}", arr.Rank)
    Console.WriteLine("arr = {0}", arr.GetLength(0))
    Console.WriteLine()

    ' 3×4個の要素を持つ2次元配列を作成
    Dim matrix(2, 3) As Integer

    Console.WriteLine("matrix.Length = {0}", matrix.Length)
    Console.WriteLine("matrix.Rank = {0}", matrix.Rank)
    Console.WriteLine("matrix = {0}×{1}", matrix.GetLength(0), matrix.GetLength(1))
    Console.WriteLine()

    ' 4×2×3個の要素を持つ3次元配列
    Dim cube(3, 1, 2) As Integer

    Console.WriteLine("cube.Length = {0}", cube.Length)
    Console.WriteLine("cube.Rank = {0}", cube.Rank)
    Console.WriteLine("cube = {0}×{1}×{2}", cube.GetLength(0), cube.GetLength(1), cube.GetLength(2))
    Console.WriteLine()

    ' 2×2×2×2個の要素を持つ4次元配列
    Dim tesseract(1, 1, 1, 1) As Integer

    Console.WriteLine("tesseract.Length = {0}", tesseract.Length)
    Console.WriteLine("tesseract.Rank = {0}", tesseract.Rank)
    Console.WriteLine("tesseract = {0}×{1}×{2}×{3}", tesseract.GetLength(0), tesseract.GetLength(1), tesseract.GetLength(2), tesseract.GetLength(3))
  End Sub
End Class
実行結果
arr.Length = 5
arr.Rank = 1
arr = 5

matrix.Length = 12
matrix.Rank = 2
matrix = 3×4

cube.Length = 24
cube.Rank = 3
cube = 4×2×3

tesseract.Length = 16
tesseract.Rank = 4
tesseract = 2×2×2×2

要素の列挙

多次元配列も1次元配列と同様for文・foreach文で列挙することができます。 ただ、foreach文で多次元配列を列挙する場合、行や列ごとといった部分配列が列挙されるのではなく、次元が平坦化された1次元の数列として列挙されます。 この際、多段配列内の各要素は、より高い次元にあるインデックスの小さい要素から順に列挙されます。 そのため、多次元配列から行や列ごとに要素を抽出したい場合は、foreach文ではなくfor文でインデックスを指定して列挙する必要があります。

for・foreachで2次元配列を列挙する
using System;

class Sample {
  static void Main()
  {
    // 3×4個の要素を持つ2次元配列
    int[,] matrix = {
      {0, 1, 2, 3},
      {4, 5, 6, 7},
      {8, 9, 10, 11},
    };

    // for文を使って列挙
    for (var d1 = 0; d1 < matrix.GetLength(0); d1++) {
      Console.Write("( ");
      for (var d2 = 0; d2 < matrix.GetLength(1); d2++) {
        Console.Write("{0}, ", matrix[d1, d2]);
      }
      Console.WriteLine("), ");
    }
    Console.WriteLine();

    // foreach文を使って列挙
    foreach (var elem in matrix) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
for・foreachで2次元配列を列挙する
Imports System

Class Sample
  Shared Sub Main()
    ' 3×4個の要素を持つ2次元配列
    Dim matrix As Integer(,) = { _
      {0, 1, 2, 3}, _
      {4, 5, 6, 7}, _
      {8, 9, 10, 11} _
    }

    ' Forステートメントを使って列挙
    For d1 As Integer = 0 To matrix.GetLength(0) - 1
      Console.Write("( ")
      For d2 As Integer = 0 To matrix.GetLength(1) - 1
        Console.Write("{0}, ", matrix(d1, d2))
      Next
      Console.WriteLine("), ")
    Next
    Console.WriteLine()

    ' For Eachステートメントを使って列挙
    For Each elem As Integer In matrix
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
( 0, 1, 2, 3, ), 
( 4, 5, 6, 7, ), 
( 8, 9, 10, 11, ), 

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 
for・foreachで3次元配列を列挙する
using System;

class Sample {
  static void Main()
  {
    // 4×2×3個の要素を持つ3次元配列
    int[,,] cube = {
      {  { 0,  1,  2},  { 3,  4,  5}  },
      {  { 6,  7,  8},  { 9, 10, 11}  },
      {  {12, 13, 14},  {15, 16, 17}  },
      {  {18, 19, 20},  {21, 22, 23}  },
    };

    // for文を使って列挙
    for (var d1 = 0; d1 < cube.GetLength(0); d1++) {
      Console.Write("{ ");
      for (var d2 = 0; d2 < cube.GetLength(1); d2++) {
        Console.Write("( ");
        for (var d3 = 0; d3 < cube.GetLength(2); d3++) {
          Console.Write("{0}, ", cube[d1, d2, d3]);
        }
        Console.Write("), ");
      }
      Console.WriteLine("}, ");
    }
    Console.WriteLine();

    // foreach文を使って列挙
    foreach (var elem in cube) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
for・foreachで3次元配列を列挙する
Imports System

Class Sample
  Shared Sub Main()
    ' 4×2×3個の要素を持つ3次元配列
    Dim cube As Integer(,,) = { _
      {  { 0,  1,  2},  { 3,  4,  5}  }, _
      {  { 6,  7,  8},  { 9, 10, 11}  }, _
      {  {12, 13, 14},  {15, 16, 17}  }, _
      {  {18, 19, 20},  {21, 22, 23}  } _
    }

    ' Forステートメントを使って列挙
    For d1 As Integer = 0 To cube.GetLength(0) - 1
      Console.Write("{ ")
      For d2 As Integer = 0 To cube.GetLength(1) - 1
        Console.Write("( ")
        For d3 As Integer = 0 To cube.GetLength(2) - 1
          Console.Write("{0}, ", cube(d1, d2, d3))
        Next
        Console.Write("), ")
      Next
      Console.WriteLine("}, ")
    Next
    Console.WriteLine()

    ' For Eachステートメントを使って列挙
    For Each elem As Integer In cube
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
{ ( 0, 1, 2, ), ( 3, 4, 5, ), }, 
{ ( 6, 7, 8, ), ( 9, 10, 11, ), }, 
{ ( 12, 13, 14, ), ( 15, 16, 17, ), }, 
{ ( 18, 19, 20, ), ( 21, 22, 23, ), }, 

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 
for・foreachで4次元配列を列挙する
using System;

class Sample {
  static void Main()
  {
    // 2×2×2×2個の要素を持つ4次元配列
    int[,,,] tesseract = {
      {  {  {0, 1},  { 2,  3}  },  {  { 4,  5},  { 6,  7}  }  },
      {  {  {8, 9},  {10, 11}  },  {  {12, 13},  {14, 15}  }  },
    };

    // for文を使って列挙
    for (var d1 = 0; d1 < tesseract.GetLength(0); d1++) {
      Console.Write("[ ");
      for (var d2 = 0; d2 < tesseract.GetLength(1); d2++) {
        Console.Write("{ ");
        for (var d3 = 0; d3 < tesseract.GetLength(2); d3++) {
          Console.Write("( ");
          for (var d4 = 0; d4 < tesseract.GetLength(3); d4++) {
            Console.Write("{0}, ", tesseract[d1, d2, d3, d4]);
          }
          Console.Write("), ");
        }
        Console.Write("}, ");
      }
      Console.WriteLine("], ");
    }
    Console.WriteLine();

    // foreach文を使って列挙
    foreach (var elem in tesseract) {
      Console.Write("{0}, ", elem);
    }
    Console.WriteLine();
  }
}
for・foreachで4次元配列を列挙する
Imports System

Class Sample
  Shared Sub Main()
    ' 2×2×2×2個の要素を持つ4次元配列
    Dim tesseract As Integer(,,,) = { _
      {  {  {0, 1},  { 2,  3}  },  {  { 4,  5},  { 6,  7}  }  }, _
      {  {  {8, 9},  {10, 11}  },  {  {12, 13},  {14, 15}  }  } _
    }

    ' Forステートメントを使って列挙
    For d1 As Integer = 0 To tesseract.GetLength(0) - 1
      Console.Write("[ ")
      For d2 As Integer = 0 To tesseract.GetLength(1) - 1
        Console.Write("{ ")
        For d3 As Integer = 0 To tesseract.GetLength(2) - 1
          Console.Write("( ")
          For d4 As Integer = 0 To tesseract.GetLength(3) - 1
            Console.Write("{0}, ", tesseract(d1, d2, d3, d4))
          Next
          Console.Write("), ")
        Next
        Console.Write("}, ")
      Next
      Console.WriteLine("], ")
    Next
    Console.WriteLine()

    ' For Eachステートメントを使って列挙
    For Each elem As Integer In tesseract
      Console.Write("{0}, ", elem)
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
[ { ( 0, 1, ), ( 2, 3, ), }, { ( 4, 5, ), ( 6, 7, ), }, ], 
[ { ( 8, 9, ), ( 10, 11, ), }, { ( 12, 13, ), ( 14, 15, ), }, ], 

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 

任意の次元数の配列を扱う例

次の例は、Lengthプロパティ・Rankプロパティ・GetLengthメソッドなどと組み合わせて多次元配列を扱う例です。 このコードでは、任意の次元数・要素数の多次元配列を引数にとり、その多次元配列の次元・長さ・要素数・格納されている全要素を表示するメソッドを実装しています。 どのような配列もArrayクラスから暗黙的に派生しているので、引数の型をArrayとすることで任意の配列を受け取れるようにしています。 また、配列内の全要素はforeach文と同じ順で列挙されるようにしています。

なお、このコードで使用しているGetValueメソッドは、引数としてインデックスを渡すことにより、配列内の該当するインデックスの値を取得することができるメソッドです。 詳しくは配列操作 §.配列の作成・要素の取得と設定 (CreateInstance, GetValue, SetValue)で解説しています。

任意の次元数・要素数の配列から、配列の次元・次元ごとの長さ・全要素数を取得する
using System;

class Sample {
  static void Print(Array arr)
  {
    Console.WriteLine("次元: {0}", arr.Rank);

    Console.Write("長さ: ");

    for (var d = 0; d < arr.Rank; d++) {
      if (0 < d)
        Console.Write("×{0}", arr.GetLength(d));
      else
        Console.Write("{0}", arr.GetLength(d));
    }

    Console.WriteLine();

    Console.WriteLine("要素数: {0}", arr.Length);

    Console.Write("要素: ");

    // 取得したい要素のインデックスを指定するための配列
    var indices = new int[arr.Rank];

    for (;;) {
      // [step1] step3でインデックスをインクリメントした結果、各次元の長さに達したかどうか調べる
      for (var d = arr.Rank - 1; 0 <= d; d--) {
        if (arr.GetLength(d) <= indices[d]) {
          // d次元目のインデックスがd次元目の長さを越えている場合
          if (d == 0) {
            // 1次元目(d = 0)の場合は、インクリメントした結果が1次元目の長さに達しているので終了する
            Console.WriteLine();
            return;
          }
          else {
            // d次元目のインデックスを0に戻し、一つ低い次元(d - 1次元)のインデックスをインクリメントする
            indices[d] = 0;
            indices[d - 1]++;
          }
        }
      }

      // [step2] 指定されたインデックスの要素を取得して表示
      Console.Write("{0}, ", arr.GetValue(indices));

      // [step3] もっとも高い次元のインデックスをインクリメント
      indices[arr.Rank - 1]++;
    }
  }

  static void Main()
  {
    // 5個の要素を持つ1次元配列
    int[] arr = {
      0, 1, 2, 3, 4,
    };

    Print(arr);
    Console.WriteLine();

    // 3×4個の要素を持つ2次元配列
    int[,] matrix = {
      {0, 1, 2, 3},
      {4, 5, 6, 7},
      {8, 9, 10, 11},
    };

    Print(matrix);
    Console.WriteLine();

    // 4×2×3個の要素を持つ3次元配列
    int[,,] cube = {
      {  { 0,  1,  2},  { 3,  4,  5}  },
      {  { 6,  7,  8},  { 9, 10, 11}  },
      {  {12, 13, 14},  {15, 16, 17}  },
      {  {18, 19, 20},  {21, 22, 23}  },
    };

    Print(cube);
    Console.WriteLine();

    // 2×2×2×2個の要素を持つ4次元配列
    int[,,,] tesseract = {
      {  {  {0, 1},  { 2,  3}  },  {  { 4,  5},  { 6,  7}  }  },
      {  {  {8, 9},  {10, 11}  },  {  {12, 13},  {14, 15}  }  },
    };

    Print(tesseract);
    Console.WriteLine();

    // 1×1×1×1×1個の要素を持つ5次元配列
    Print(new int[1, 1, 1, 1, 1]);
    Console.WriteLine();

    // 1×0×1×0×1×0個の要素を持つ6次元配列
    Print(new int[1, 0, 1, 0, 1, 0]);
    Console.WriteLine();
  }
}
任意の次元数・要素数の配列から、配列の次元・次元ごとの長さ・全要素数を取得する
Imports System

Class Sample
  Shared Sub Print(ByVal arr As Array)
    Console.WriteLine("次元: {0}", arr.Rank)

    Console.Write("長さ: ")

    For d As Integer = 0 To arr.Rank - 1
      If 0 < d Then
        Console.Write("×{0}", arr.GetLength(d))
      Else
        Console.Write("{0}", arr.GetLength(d))
      End If
    Next

    Console.WriteLine()

    Console.WriteLine("要素数: {0}", arr.Length)

    Console.Write("要素: ")

    ' 取得したい要素のインデックスを指定するための配列
    Dim indices(arr.Rank - 1) As Integer

    Do
      ' [step1] step3でインデックスをインクリメントした結果、各次元の長さに達したかどうか調べる
      For d As Integer = arr.Rank - 1 To 0 Step -1
        If arr.GetLength(d) <= indices(d) Then
          ' d次元目のインデックスがd次元目の長さを越えている場合
          If d = 0 Then
            ' 1次元目(d = 0)の場合は、インクリメントした結果が1次元目の長さに達しているので終了する
            Console.WriteLine()
            Return
          Else
            ' d次元目のインデックスを0に戻し、一つ低い次元(d - 1次元)のインデックスをインクリメントする
            indices(d) = 0
            indices(d - 1) += 1
          End if
        End If
      Next

      ' [step2] 指定されたインデックスの要素を取得して表示
      Console.Write("{0}, ", arr.GetValue(indices))

      ' [step3] もっとも高い次元のインデックスをインクリメント
      indices(arr.Rank - 1) += 1
    Loop
  End Sub

  Shared Sub Main()
    ' 5個の要素を持つ1次元配列
    Dim arr As Integer() = { _
      0, 1, 2, 3, 4 _
    }

    Print(arr)
    Console.WriteLine()

    ' 3×4個の要素を持つ2次元配列
    Dim matrix As Integer(,) = { _
      {0, 1, 2, 3}, _
      {4, 5, 6, 7}, _
      {8, 9, 10, 11} _
    }

    Print(matrix)
    Console.WriteLine()

    ' 4×2×3個の要素を持つ3次元配列
    Dim cube As Integer(,,) = { _
      {  { 0,  1,  2},  { 3,  4,  5}  }, _
      {  { 6,  7,  8},  { 9, 10, 11}  }, _
      {  {12, 13, 14},  {15, 16, 17}  }, _
      {  {18, 19, 20},  {21, 22, 23}  } _
    }

    Print(cube)
    Console.WriteLine()

    ' 2×2×2×2個の要素を持つ4次元配列
    Dim tesseract As Integer(,,,) = { _
      {  {  {0, 1},  { 2,  3}  },  {  { 4,  5},  { 6,  7}  }  }, _
      {  {  {8, 9},  {10, 11}  },  {  {12, 13},  {14, 15}  }  } _
    }

    Print(tesseract)
    Console.WriteLine()

    ' 1×1×1×1×1個の要素を持つ5次元配列
    Print(New Integer(0, 0, 0, 0, 0) {})
    Console.WriteLine()

    ' 1×0×1×0×1×0個の要素を持つ6次元配列
    Print(New Integer(0, -1, 0, -1, 0, -1) {})
    Console.WriteLine()
  End Sub
End Class
実行結果
次元: 1
長さ: 5
要素数: 5
要素: 0, 1, 2, 3, 4, 

次元: 2
長さ: 3×4
要素数: 12
要素: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 

次元: 3
長さ: 4×2×3
要素数: 24
要素: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 

次元: 4
長さ: 2×2×2×2
要素数: 16
要素: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 

次元: 5
長さ: 1×1×1×1×1
要素数: 1
要素: 0, 

次元: 6
長さ: 1×0×1×0×1×0
要素数: 0
要素: 

ジャグ配列 (多段配列)

宣言・作成・要素の参照

2段のジャグ配列を宣言・作成し、要素を参照する例について見てみます。 次の例では、1段目の長さが3、2段目の長さが各々3, 2, 4の計9個の要素を持つ2段のジャグ配列を作成しています。

2段ジャグ配列の作成・2段ジャグ配列要素の参照
using System;

class Sample {
  static void Main()
  {
    // 1段目の長さが3である2段のジャグ配列を作成
    int[][] jagged = new int[3][];

    // 作成したジャグ配列の1段目に、2段目となる配列を代入
    jagged[0] = new int[3]; // 1段目の0番目に長さが3の配列を代入
    jagged[1] = new int[2]; // 1段目の1番目に長さが2の配列を代入
    jagged[2] = new int[4]; // 1段目の2番目に長さが4の配列を代入

    // 1段目のインデックスが0、2段目のインデックスが0の要素に値を設定
    jagged[0][0] = 0;

    // 1段目のインデックスが2、2段目のインデックスが3の要素に値を設定
    jagged[2][3] = 8;
  }
}

2段ジャグ配列の作成・2段ジャグ配列要素の参照
Imports System

Class Sample
  Shared Sub Main()
    ' 1段目の長さが3である2段のジャグ配列を作成
    Dim jagged(2)() As Integer

    ' 作成したジャグ配列の1段目に、2段目となる配列を代入
    jagged(0) = New Integer(2) {} ' 1段目の0番目に長さが3の配列を代入
    jagged(1) = New Integer(1) {} ' 1段目の1番目に長さが2の配列を代入
    jagged(2) = New Integer(3) {} ' 1段目の2番目に長さが4の配列を代入

    ' 1段目のインデックスが0、2段目のインデックスが0の要素に値を設定
    jagged(0)(0) = 0

    ' 1段目のインデックスが2、2段目のインデックスが3の要素に値を設定
    jagged(2)(3) = 8
  End Sub
End Class

2段のジャグ配列を宣言する場合は、1段目の要素数(またはインデックスの最大値)と、要素数を空にした2段目を括弧を連ねて記述します。 2段目に要素数を指定することはできません。 このように宣言されたジャグ配列では、2段目の配列はまだ作成されておらずヌル参照(null/Nothing)となっています。 そこからさらに2段目となる配列を1段目に代入していくことで、2段のジャグ配列を構成することができます。

2段のジャグ配列内の各要素を参照する場合は、1段目と2段目のインデックスを括弧を連ねて記述します。 上記のコードで作成される2段のジャグ配列を図式化すると次のようになります。 1段目を縦方向、2段目を横方向で表しています。

1段目の長さが3の2段のジャグ配列のイメージ
jagged[0] → jagged[0][0]jagged[0][1]jagged[0][2]
jagged[1] → jagged[1][0]jagged[1][1]
jagged[2] → jagged[2][0]jagged[2][1]jagged[2][2]jagged[2][3]

初期値を与えてジャグ配列を初期化する方法、ジャグ配列における配列初期化子については§.初期化 (配列初期化子)で解説します。

3段以上のジャグ配列を宣言・作成する場合も同様に、まず1段目の要素数のみを指定し、段数分だけ括弧を連ねて記述します。 そこから2段目となる配列の代入、さらにそこへ3段目となる配列を代入…と繰り替えしていきます。 要素を参照する場合も同様に、[1段目][2段目][3段目][…]と段数分だけ括弧を連ねて記述します。

3段ジャグ配列の作成・3段ジャグ配列要素の参照
using System;

class Sample {
  static void Main()
  {
    // 1段目の長さが3である3段のジャグ配列を作成
    int[][][] doubleNested = new int[3][][];

    // 1段目に2段目となる配列を代入
    doubleNested[2] = new int[2][]; // 1段目の2番目に長さが2で2段のジャグ配列を代入

    // 2段目に3段目となる配列を代入
    doubleNested[2][0] = new int[4]; // 1段目の0番目、2段目の0番目に長さが4の配列を代入

    // 3段目の要素に値を代入
    doubleNested[2][0][3] = 5;
  }
}
3段ジャグ配列の作成・3段ジャグ配列要素の参照
Imports System

Class Sample
  Shared Sub Main()
    ' 1段目の長さが3である3段のジャグ配列を作成
    Dim doubleNested(2)()() As Integer

    ' 1段目に2段目となる配列を代入
    doubleNested(2) = New Integer(1)() {} ' 1段目の2番目に長さが2で2段のジャグ配列を代入

    ' 2段目に3段目となる配列を代入
    doubleNested(2)(0) = New Integer(3) {} ' 1段目の0番目、2段目の0番目に長さが4の配列を代入

    ' 3段目の要素に値を代入
    doubleNested(2)(0)(3) = 5
  End Sub
End Class
4段ジャグ配列の作成・4段ジャグ配列要素の参照
using System;

class Sample {
  static void Main()
  {
    // 1段目の長さが2である4段のジャグ配列を作成
    int[][][][] tripleNested = new int[2][][][];

    // 1段目に2段目となる配列を代入
    tripleNested[1] = new int[1][][]; // 1段目の1番目に長さが1で3段のジャグ配列を代入

    // 2段目に3段目となる配列を代入
    tripleNested[1][0] = new int[3][]; // 1段目の1番目、2段目の0番目に長さが3で2段のジャグ配列を代入

    // 3段目に4段目となる配列を代入
    tripleNested[1][0][2] = new int[2]; // 1段目の1番目、2段目の0番目、3段目の2番目に長さが2の配列を代入

    // 4段目の要素に値を代入
    tripleNested[1][0][2][1] = 16;
  }
}
4段ジャグ配列の作成・4段ジャグ配列要素の参照
Imports System

Class Sample
  Shared Sub Main()
    ' 1段目の長さが2である4段のジャグ配列を作成
    Dim tripleNested(1)()()() As Integer

    ' 1段目に2段目となる配列を代入
    tripleNested(1) = New Integer(0)()() {} ' 1段目の1番目に長さが1で3段のジャグ配列を代入

    ' 2段目に3段目となる配列を代入
    tripleNested(1)(0) = New Integer(2)() {} ' 1段目の1番目、2段目の0番目に長さが3で2段のジャグ配列を代入

    ' 3段目に4段目となる配列を代入
    tripleNested(1)(0)(2) = New Integer(1) {} ' 1段目の1番目、2段目の0番目、3段目の2番目に長さが2の配列を代入

    ' 4段目の要素に値を代入
    tripleNested(1)(0)(2)(1) = 16
  End Sub
End Class

ジャグ配列は配列の配列であることから、宣言等の記述を次のように読み替えることもできます。

ジャグ配列の記述の読み替え
配列 記述 読み替え
2段のジャグ配列 int[][] int 型の 配列 [] の配列 []
もしくは
「1段のジャグ配列 int[] に 配列 [] を含めるようにしたもの」
3段のジャグ配列 int[][][] int 型の 配列 [] の配列 [] の配列 []
もしくは
「2段のジャグ配列 int[][] に 配列 [] を含めるようにしたもの」
4段のジャグ配列 int[][][][] int 型の 配列 [] の配列 [] の配列 [] の配列 []
もしくは
「3段のジャグ配列 int[][][] に 配列 [] を含めるようにしたもの」

宣言されているものと異なる段数の配列を代入しようとするとコンパイル時にエラーとなります。

段数の異なるジャグ配列を代入しようとした場合、コンパイルエラーとなる
using System;

class Sample {
  static void Main()
  {
    // 3段のジャグ配列
    int[][][] doubleNested = new int[3][][];

    // 2段のジャグ配列を格納する変数
    int[][] jagged;

    // sample.cs(13,14): error CS0029: 型 'int[][][]' を型 'int[][]' に暗黙的に変換できません。
    jagged = doubleNested;
  }
}
段数の異なるジャグ配列を代入しようとした場合、コンパイルエラーとなる
Imports System

Class Sample
  Shared Sub Main()
    ' 3段のジャグ配列
    Dim doubleNested(2)()() As Integer

    ' 2段のジャグ配列を格納する変数
    Dim jagged()() As Integer

    ' E:\sample.vb(12) : error BC30332: 'Integer の 1 次元配列 の 1 次元配列' は 'Integer の 1 次元配列' から派生していないため、型 'Integer の 1 次元配列 の 1 次元配列 の 1 次元配列' の値を 'Integer の 1 次元配列 の 1 次元配列' に変換できません。
    jagged = doubleNested
  End Sub
End Class

初期化 (配列初期化子)

ジャグ配列の場合でも配列初期化子を使って初期化することができます。 配列初期化子を使って初期化する場合、多次元配列の場合と同様の記述ができますが、1段目はnewを省略して記述できるのに対し、2段目以降はnewを省略して記述することはできないという点に注意が必要です。

次の例では、1段目の長さが3、2段目の長さが各々3, 2, 4の計9個の要素を持つ2段のジャグ配列を作成すると同時に初期化を行っています。

配列初期化子を使って2段ジャグ配列を初期化する
using System;

class Sample {
  static void Main()
  {
    // 1段目の長さが3、2段目の長さが各々3, 2, 4の2段のジャグ配列を作成
    int[][] jagged = {
      new int[] {0, 1, 2},
      new int[] {3, 4},
      new int[] {5, 6, 7, 8},
    };

    Console.WriteLine("jagged[0][0] = {0}", jagged[0][0]);
    Console.WriteLine("jagged[0][1] = {0}", jagged[0][1]);
    Console.WriteLine("jagged[1][0] = {0}", jagged[1][0]);
    Console.WriteLine("jagged[2][3] = {0}", jagged[2][3]);
  }
}
配列初期化子を使って2段ジャグ配列を初期化する
Imports System

Class Sample
  Shared Sub Main()
    ' 1段目の長さが3、2段目の長さが各々3, 2, 4の2段のジャグ配列を作成
    Dim jagged()() As Integer = { _
      New Integer() {0, 1, 2}, _
      New Integer() {3, 4}, _
      New Integer() {5, 6, 7, 8} _
    }

    Console.WriteLine("jagged(0)(0) = {0}", jagged(0)(0))
    Console.WriteLine("jagged(0)(1) = {0}", jagged(0)(1))
    Console.WriteLine("jagged(1)(0) = {0}", jagged(1)(0))
    Console.WriteLine("jagged(2)(3) = {0}", jagged(2)(3))
  End Sub
End Class
実行結果
jagged[0][0] = 0
jagged[0][1] = 1
jagged[1][0] = 3
jagged[2][3] = 8

このコードで作成・初期化される2段のジャグ配列を図式化すると次のようになります。

初期化後に2段のジャグ配列へ格納される値のイメージ
jagged[0] → 012
jagged[1] → 34
jagged[2] → 5678

3段以上のジャグ配列も同様にして初期化することができます。 配列の中に配列を含めるよう入れ子に記述していくことで多段のジャグ配列を初期化できます。

配列初期化子を使って3段ジャグ配列を初期化する
using System;

class Sample {
  static void Main()
  {
    // 3段のジャグ配列
    int[][][] doubleNested = {
      new int[][] {
        new int[] {0, 1, 2},
        new int[] {3, 4},
        new int[] {5, 6, 7, 8},
      },
      new int[][] {
        new int[] {9, 10},
        new int[] {11, 12, 13, 14},
      },
      new int[][] {
        new int[] {15, 16, 17},
        new int[] {18},
        new int[] {19, 20},
        new int[] {21, 22},
      },
    };

    Console.WriteLine("doubleNested[0][0][0] = {0}", doubleNested[0][0][0]);
    Console.WriteLine("doubleNested[0][2][3] = {0}", doubleNested[0][2][3]);
    Console.WriteLine("doubleNested[1][0][0] = {0}", doubleNested[1][0][0]);
    Console.WriteLine("doubleNested[2][3][1] = {0}", doubleNested[2][3][1]);
  }
}
配列初期化子を使って3段ジャグ配列を初期化する
Imports System

Class Sample
  Shared Sub Main()
    ' 3段のジャグ配列
    Dim doubleNested()()() As Integer = { _
      New Integer()() { _
        New Integer() {0, 1, 2}, _
        New Integer() {3, 4}, _
        New Integer() {5, 6, 7, 8} _
      }, _
      New Integer()() { _
        New Integer() {9, 10}, _
        New Integer() {11, 12, 13, 14} _
      }, _
      New Integer()() { _
        New Integer() {15, 16, 17}, _
        New Integer() {18}, _
        New Integer() {19, 20}, _
        New Integer() {21, 22} _
      } _
    }

    Console.WriteLine("doubleNested(0)(0)(0) = {0}", doubleNested(0)(0)(0))
    Console.WriteLine("doubleNested(0)(2)(3) = {0}", doubleNested(0)(2)(3))
    Console.WriteLine("doubleNested(1)(0)(0) = {0}", doubleNested(1)(0)(0))
    Console.WriteLine("doubleNested(2)(3)(1) = {0}", doubleNested(2)(3)(1))
  End Sub
End Class
実行結果
doubleNested[0][0][0] = 0
doubleNested[0][2][3] = 8
doubleNested[1][0][0] = 9
doubleNested[2][3][1] = 22

長さの取得

多次元配列のLengthプロパティとは異なり、ジャグ配列ではLengthプロパティを参照しても全要素を取得することはできません。 また、ジャグ配列では各段で長さが異なる場合があることから、GetLengthメソッドを使って2段目以降の長さを取得するといったこともできません。

ジャグ配列の場合、Lengthプロパティは1次元配列と同様、1段目の長さを返します。

ジャグ配列1段目の長さを取得する
using System;

class Sample {
  static void Main()
  {
    // 1段目の長さが3である2段のジャグ配列
    int[][] jagged = new int[3][];

    Console.WriteLine("jagged.Length = {0}", jagged.Length);

    // 1段目の長さが3である3段のジャグ配列
    int[][][] doubleNested = new int[3][][];

    Console.WriteLine("doubleNested.Length = {0}", doubleNested.Length);

    // 1段目の長さが2である4段のジャグ配列
    int[][][][] tripleNested = new int[2][][][];

    Console.WriteLine("tripleNested.Length = {0}", tripleNested.Length);
  }
}
ジャグ配列1段目の長さを取得する
Imports System

Class Sample
  Shared Sub Main()
    ' 1段目の長さが3である2段のジャグ配列
    Dim jagged(2)() As Integer

    Console.WriteLine("jagged.Length = {0}", jagged.Length)

    ' 1段目の長さが3である3段のジャグ配列
    Dim doubleNested(2)()() As Integer

    Console.WriteLine("doubleNested.Length = {0}", doubleNested.Length)

    ' 1段目の長さが2である4段のジャグ配列
    Dim tripleNested(1)()()() As Integer

    Console.WriteLine("tripleNested.Length = {0}", tripleNested.Length)
  End Sub
End Class
実行結果
jagged.Length = 3
doubleNested.Length = 3
tripleNested.Length = 2

2段目以降の長さを取得する場合は、ジャグ配列内に格納されている配列のLengthプロパティを個別に参照する必要があります。

ジャグ配列2段目の長さを取得する
using System;

class Sample {
  static void Main()
  {
    // 2段のジャグ配列
    int[][] jagged = {
      new int[] {0, 1, 2},
      new int[] {3, 4},
      new int[] {5, 6, 7, 8},
    };

    Console.WriteLine("jagged[0].Length = {0}", jagged[0].Length);
    Console.WriteLine("jagged[1].Length = {0}", jagged[1].Length);
    Console.WriteLine("jagged[2].Length = {0}", jagged[2].Length);
  }
}
ジャグ配列2段目の長さを取得する
Imports System

Class Sample
  Shared Sub Main()
    ' 2段のジャグ配列
    Dim jagged()() As Integer = { _
      New Integer() {0, 1, 2}, _
      New Integer() {3, 4}, _
      New Integer() {5, 6, 7, 8} _
    }

    Console.WriteLine("jagged(0).Length = {0}", jagged(0).Length)
    Console.WriteLine("jagged(1).Length = {0}", jagged(1).Length)
    Console.WriteLine("jagged(2).Length = {0}", jagged(2).Length)
  End Sub
End Class
実行結果
jagged[0].Length = 3
jagged[1].Length = 2
jagged[2].Length = 4

要素の列挙

ジャグ配列も1次元配列と同様for文・foreach文で列挙することができます。 ただし、foreach文でジャグ配列を列挙する場合は、多次元配列のように配列内の全要素が一つずつ列挙されるのではなく、単にジャグ配列の1段目に格納されている配列が列挙されます。 そのため、ジャグ配列内のすべての要素を列挙したい場合は、for文・foreach文ともに各段それぞれでfor文・foreach文を入れ子にしていくことで列挙する必要があります。

for・foreachで2段ジャグ配列を列挙する
using System;

class Sample {
  static void Main()
  {
    // 2段のジャグ配列
    int[][] jagged = {
      new int[] {0, 1, 2},
      new int[] {3, 4},
      new int[] {5, 6, 7, 8},
    };

    // for文を使って列挙
    for (var n1 = 0; n1 < jagged.Length; n1++) {
      Console.Write("( ");
      for (var n2 = 0; n2 < jagged[n1].Length; n2++) {
        Console.Write("{0}, ", jagged[n1][n2]);
      }
      Console.WriteLine("), ");
    }
    Console.WriteLine();

    // foreach文を使って列挙
    foreach (int[] arr in jagged) {
      Console.Write("( ");
      foreach (int elem in arr) {
        Console.Write("{0}, ", elem);
      }
      Console.WriteLine("), ");
    }
    Console.WriteLine();
  }
}
for・foreachで2段ジャグ配列を列挙する
Imports System

Class Sample
  Shared Sub Main()
    ' 2段のジャグ配列
    Dim jagged()() As Integer = { _
      New Integer() {0, 1, 2}, _
      New Integer() {3, 4}, _
      New Integer() {5, 6, 7, 8} _
    }

    ' Forステートメントを使って列挙
    For n1 As Integer = 0 To jagged.Length - 1
      Console.Write("( ")
      For n2 As Integer = 0 To jagged(n1).Length - 1
        Console.Write("{0}, ", jagged(n1)(n2))
      Next
      Console.WriteLine("), ")
    Next
    Console.WriteLine()

    ' For Eachステートメントを使って列挙
    For Each arr As Integer() In jagged
      Console.Write("( ")
      For Each elem As Integer In arr
        Console.Write("{0}, ", elem)
      Next
      Console.WriteLine("), ")
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
( 0, 1, 2, ), 
( 3, 4, ), 
( 5, 6, 7, 8, ), 

( 0, 1, 2, ), 
( 3, 4, ), 
( 5, 6, 7, 8, ), 

for・foreachで3段ジャグ配列を列挙する
using System;

class Sample {
  static void Main()
  {
    // 3段のジャグ配列
    int[][][] doubleNested = {
      new int[][] {
        new int[] {0, 1, 2},
        new int[] {3, 4},
        new int[] {5, 6, 7, 8},
      },
      new int[][] {
        new int[] {9, 10},
        new int[] {11, 12, 13, 14},
      },
      new int[][] {
        new int[] {15, 16, 17},
        new int[] {18},
        new int[] {19, 20},
        new int[] {21, 22},
      },
    };

    // for文を使って列挙
    for (var n1 = 0; n1 < doubleNested.Length; n1++) {
      Console.Write("{ ");
      for (var n2 = 0; n2 < doubleNested[n1].Length; n2++) {
        Console.Write("( ");
        for (var n3 = 0; n3 < doubleNested[n1][n2].Length; n3++) {
          Console.Write("{0}, ", doubleNested[n1][n2][n3]);
        }
        Console.Write("), ");
      }
      Console.WriteLine("}, ");
    }
    Console.WriteLine();

    // foreach文を使って列挙
    foreach (int[][] jagged in doubleNested) {
      Console.Write("{ ");
      foreach (int[] arr in jagged) {
        Console.Write("( ");
        foreach (int elem in arr) {
          Console.Write("{0}, ", elem);
        }
        Console.Write("), ");
      }
      Console.WriteLine("}, ");
    }
    Console.WriteLine();
  }
}
for・foreachで3段ジャグ配列を列挙する
Imports System

Class Sample
  Shared Sub Main()
    ' 3段のジャグ配列
    Dim doubleNested()()() As Integer = { _
      New Integer()() { _
        New Integer() {0, 1, 2}, _
        New Integer() {3, 4}, _
        New Integer() {5, 6, 7, 8} _
      }, _
      New Integer()() { _
        New Integer() {9, 10}, _
        New Integer() {11, 12, 13, 14} _
      }, _
      New Integer()() { _
        New Integer() {15, 16, 17}, _
        New Integer() {18}, _
        New Integer() {19, 20}, _
        New Integer() {21, 22} _
      } _
    }

    ' Forステートメントを使って列挙
    For n1 As Integer = 0 To doubleNested.Length - 1
      Console.Write("{ ")
      For n2 As Integer = 0 To doubleNested(n1).Length - 1
        Console.Write("( ")
        For n3 As Integer = 0 To doubleNested(n1)(n2).Length - 1
          Console.Write("{0}, ", doubleNested(n1)(n2)(n3))
        Next
        Console.Write("), ")
      Next
      Console.WriteLine("}, ")
    Next
    Console.WriteLine()

    ' For Eachステートメントを使って列挙
    For Each jagged As Integer()() In doubleNested
      Console.Write("{ ")
      For Each arr As Integer() In jagged
        Console.Write("( ")
        For Each elem As Integer In arr
          Console.Write("{0}, ", elem)
        Next
        Console.Write("), ")
      Next
      Console.WriteLine("), ")
    Next
    Console.WriteLine()
  End Sub
End Class
実行結果
{ ( 0, 1, 2, ), ( 3, 4, ), ( 5, 6, 7, 8, ), }, 
{ ( 9, 10, ), ( 11, 12, 13, 14, ), }, 
{ ( 15, 16, 17, ), ( 18, ), ( 19, 20, ), ( 21, 22, ), }, 

{ ( 0, 1, 2, ), ( 3, 4, ), ( 5, 6, 7, 8, ), }, 
{ ( 9, 10, ), ( 11, 12, 13, 14, ), }, 
{ ( 15, 16, 17, ), ( 18, ), ( 19, 20, ), ( 21, 22, ), }, 

多次元配列のジャグ配列・ジャグ配列の多次元配列・多次元配列の多次元配列

多次元配列の要素の型をジャグ配列にすることにより、ジャグ配列の多次元配列を構築することができます。 また逆に、ジャグ配列の要素の型を多次元配列にすることにより、多次元配列のジャグ配列を構築することもできます。 さらに、多次元配列の多次元配列も構築することができます。

一般に、このようなデータ型が必要になる場合はまれで、必要になったとしてもよりシンプルなデータ型で表現可能である場合がほとんどだと思われます。 以下はあくまでこのようなことも可能ということを示す目的で、多次元配列のジャグ配列・ジャグ配列の多次元配列・多次元配列の多次元配列を構築する例をあげます。

2次元配列の2段ジャグ配列を構築する
using System;

class Sample {
  static void Main()
  {
    // 2次元配列の2段ジャグ配列
    int[][][,] jaggedMultidimensional = {
      new int[][,] {
        // [0][0][,]
        new int[,] {
          {0, 1},
          {2, 3}
        }, 
        // [0][1][,]
        new int[,] {
          {4, 5},
          {6, 7}
        }, 
      },
      new int[][,] {
        // [1][0][,]
        new int[,] {
          {8, 9},
          {10, 11}
        }
      },
    };

    Console.WriteLine(jaggedMultidimensional[0][0][1, 1]);
    Console.WriteLine(jaggedMultidimensional[0][1][1, 1]);
    Console.WriteLine(jaggedMultidimensional[1][0][1, 1]);
  }
}
2次元配列の2段ジャグ配列を構築する
Imports System

Class Sample
  Shared Sub Main()
    ' 2次元配列の2段ジャグ配列
    Dim jaggedMultidimensional As Integer()()(,) = { _
      New Integer()(,) { _
        New Integer(,) { _ ' (0)(0)(,)
          {0, 1}, _
          {2, 3}  _
        },  _
        New Integer(,) { _ ' // (0)(1)(,)
          {4, 5}, _
          {6, 7} _
        }  _
      }, _
      New Integer()(,) { _
        New Integer(,) { _ ' (1)(0)(,) _
          {8, 9}, _
          {10, 11} _
        } _
      } _
    }

    Console.WriteLine(jaggedMultidimensional(0)(0)(1, 1))
    Console.WriteLine(jaggedMultidimensional(0)(1)(1, 1))
    Console.WriteLine(jaggedMultidimensional(1)(0)(1, 1))
  End Sub
End Class
実行結果
3
7
11
2段ジャグ配列の2次元配列を構築する
using System;

class Sample {
  static void Main()
  {
    // 2段ジャグ配列の2次元配列
    int[,][][] multidimensionalJagged = {
      {
        // [0, 0][][]
        new int[][] {
          new int[] {0, 1},
          new int[] {2},
        },
        // [0, 1][][]
        new int[][] {
          new int[] {3}
        }
      },
      {
        // [1, 0][][]
        new int[][] {
          new int[] {4, 5},
        },
        // [1, 1][][]
        new int[][] {
          new int[] {6, 7},
          new int[] {8},
          new int[] {9, 10, 11},
        },
      }
    };

    Console.WriteLine(multidimensionalJagged[0, 0][0][1]);
    Console.WriteLine(multidimensionalJagged[1, 0][0][0]);
    Console.WriteLine(multidimensionalJagged[1, 1][2][2]);
  }
}
2段ジャグ配列の2次元配列を構築する
Imports System

Class Sample
  Shared Sub Main()
    ' 2段ジャグ配列の2次元配列
    Dim multidimensionalJagged As Integer(,)()() = { _
      { _
        New Integer()() { _ ' (0, 0)()()
          New Integer() {0, 1}, _
          New Integer() {2} _
        }, _
        New Integer()() { _ ' (0, 1)()()
          New Integer() {3} _
        } _
      }, _
      { _
        New Integer()() { _ ' (1, 0)()()
          New Integer() {4, 5} _
        }, _
        New Integer()() { _ ' (1, 1)()()
          New Integer() {6, 7}, _
          New Integer() {8}, _
          New Integer() {9, 10, 11} _
        } _
      } _
    }

    Console.WriteLine(multidimensionalJagged(0, 0)(0)(1))
    Console.WriteLine(multidimensionalJagged(1, 0)(0)(0))
    Console.WriteLine(multidimensionalJagged(1, 1)(2)(2))
  End Sub
End Class
実行結果
1
4
11
2次元配列の2次元配列を構築する
using System;

class Sample {
  static void Main()
  {
    // 2次元配列の2次元配列
    int[,][,] multiMultiDimensional = {
      {
        // [0, 0][,]
        new int[,] {
          {0, 1},
          {2, 3},
        },
        // [0, 1][,]
        new int[,] {
          {4, 5},
          {6, 7},
        },
      },
      {
        // [1, 0][,]
        new int[,] {
          {8, 9},
          {10, 11},
        },
        // [1, 1][,]
        new int[,] {
          {12, 13},
          {14, 15},
        }
      }
    };

    Console.WriteLine(multiMultiDimensional[0, 0][0, 0]);
    Console.WriteLine(multiMultiDimensional[0, 1][1, 1]);
    Console.WriteLine(multiMultiDimensional[1, 0][0, 0]);
    Console.WriteLine(multiMultiDimensional[1, 1][1, 1]);
  }
}

2次元配列の2次元配列を構築する
Imports System

Class Sample
  Shared Sub Main()
    ' 2次元配列の2次元配列
    Dim multiMultiDimensional As Integer(,)(,) = { _
      { _
        New Integer(,) { _ ' (0, 0)(,)
          {0, 1}, _
          {2, 3} _
        }, _
        New Integer(,) { _ ' (0, 1)(,)
          {4, 5}, _
          {6, 7} _
        } _
      }, _
      { _
        New Integer(,) { _ ' (1, 0)(,)
          {8, 9}, _
          {10, 11} _
        }, _
        New Integer(,) { _ ' (1, 1)(,)
          {12, 13}, _
          {14, 15} _
        } _
      } _
    }

    Console.WriteLine(multiMultiDimensional(0, 0)(0, 0))
    Console.WriteLine(multiMultiDimensional(0, 1)(1, 1))
    Console.WriteLine(multiMultiDimensional(1, 0)(0, 0))
    Console.WriteLine(multiMultiDimensional(1, 1)(1, 1))
  End Sub
End Class

実行結果
0
7
8
15

配列・多次元配列・ジャグ配列を分類する

実行時にオブジェクトが配列か、多次元配列か、多段ジャグ配列かどうかを調べるたい場合、型情報(Type)を参照することで検証することができます。

型情報からは、まずType.IsArrayプロパティによって、型が配列(多次元配列・多段ジャグ配列を含む)かどうかを判別することができます。 また、Array.Rankプロパティを参照することにより、Rankが1なら配列またはジャグ配列、2以上なら多次元配列として分類することができます。 さらに、Type.GetElementTypeメソッドを呼び出すことにより、配列の要素の型を取得することができるため、1次元の配列なのかジャグ配列なのか、またジャグ配列の場合は何段なのかを知ることができます。

これを具体的なコードにすると、次のようになります。

オブジェクトが配列か多次元配列かジャグ配列かを判別する
using System;

class Sample {
  static void Main()
  {
    PrintTypeOfArray(new int[0]);
    PrintTypeOfArray(new int[0, 0]);
    PrintTypeOfArray(new int[0, 0, 0]);
    PrintTypeOfArray(new int[1][] { new int[0] });
    PrintTypeOfArray(new int[1][][] { new int[1][] { new int[0] } });
    PrintTypeOfArray(0);
    PrintTypeOfArray(null);
  }

  // 引数で与えられるオブジェクトから、配列の種類を分類して表示する
  static void PrintTypeOfArray(object o)
  {
    if (o is null) {
      Console.WriteLine("nullです");
      return;
    }

    // 型情報を取得する
    var t = o.GetType();

    // 型が配列かどうか
    if (!t.IsArray) {
      Console.WriteLine($"配列ではありません ({t})");
      return;
    }

    // 配列(Array)にキャスト
    var arr = (Array)o;

    // 配列は多次元化かどうか
    if (1 < arr.Rank) {
      Console.WriteLine($"{arr.Rank}次元配列です ({t})");
    }
    else {
      // 配列が1次元の場合、配列の要素の型が配列となっているか
      // どうかを再帰的に調べ、同時にその段数も調べる
      var nest = 1;
      var te = t;

      for (;;) {
        te = te.GetElementType();

        // 配列の要素の型が配列かどうか
        if (te.IsArray)
          nest++; // 段数を計上する
        else
          break;
      }

      if (nest == 1)
        Console.WriteLine($"配列です ({t})");
      else
        Console.WriteLine($"{nest}段のジャグ配列です ({t})");
    }
  }
}
オブジェクトが配列か多次元配列かジャグ配列かを判別する
Imports System
Imports System.Collections.Generic

Class Sample
  Shared Sub Main()
    PrintTypeOfArray(New Integer() {})
    PrintTypeOfArray(New Integer(,) {{}})
    PrintTypeOfArray(New Integer(,,) {{{}}})
    PrintTypeOfArray(New Integer()() { New Integer() {} })
    PrintTypeOfArray(New Integer()()() { New Integer()() { New Integer() {} } })
    PrintTypeOfArray(0)
    PrintTypeOfArray(Nothing)
  End Sub

  ' 引数で与えられるオブジェクトから、配列の種類を分類して表示する
  Shared Sub PrintTypeOfArray(ByVal o As Object)
    If o Is Nothing Then
      Console.WriteLine("Nothingです")
      Return
    End If

    ' 型情報を取得する
    Dim t As Type = o.GetType()

    ' 型が配列かどうか
    If Not t.IsArray Then
      Console.WriteLine($"配列ではありません ({t})")
      Return
    End If

    ' 配列(Array)にキャスト
    Dim arr As Array = DirectCast(o, Array)

    ' 配列は多次元化かどうか
    If 1 < arr.Rank Then
      Console.WriteLine($"{arr.Rank}次元配列です ({t})")
    Else
      ' 配列が1次元の場合、配列の要素の型が配列となっているか
      ' どうかを再帰的に調べ、同時にその段数も調べる
      Dim nest As Integer = 1
      Dim te As Type = t

      Do
        te = te.GetElementType()

        ' 配列の要素の型が配列かどうか
        If te.IsArray Then
          nest += 1 ' 段数を計上する
        Else
          Exit Do
        End If
      Loop

      If nest = 1 Then
        Console.WriteLine($"配列です ({t})")
      Else
        Console.WriteLine($"{nest}段のジャグ配列です ({t})")
      End If
    End If
  End Sub
End Class
実行結果
配列です (System.Int32[])
2次元配列です (System.Int32[,])
3次元配列です (System.Int32[,,])
2段ジャグ配列です (System.Int32[][])
3段ジャグ配列です (System.Int32[][][])
配列ではありません (System.Int32)
Nothingです