.NETでは、単純な配列(1次元配列)だけでなく、矩形の構造を持つ多次元配列(矩形配列)と、配列が入れ子になった構造を持つジャグ配列(多段配列・配列の配列)を扱うことができます。
多次元配列とジャグ配列
多次元配列は通常の配列(1次元配列)の次元を拡張したもので、マトリックスやグリッド、テーブルの様な矩形の構造を持ったデータ構造であることから、矩形配列とも呼ばれます。 (§.多次元配列 (矩形配列))
一方、ジャグ配列は配列を格納することができる配列(配列の配列)であり、その事から多段配列とも呼ばれます。 ジャグ配列は、常に矩形である多次元配列とは異なり構造がギザギザ(jagged)になることが、その名前の由来となっています。 (§.ジャグ配列 (多段配列))
ジャグ配列は多次元配列とは異なり、異なる要素数の配列を格納することができます。 例えば、2次元配列が持ちうる要素数は1次元目の長さがn、2次元目の長さがm個とすると計n×m個となり、常に次元ごとの長さの積が全要素数となります。 一方、2段のジャグ配列ではa個の配列+b個の配列+c個の配列…とジャグ配列内に格納されている配列の要素数の和となります。
// (通常の/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},
};
' (通常の/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 |
0 | 1 | 2 | 3 |
4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 |
0 1 2 |
3 4 |
5 6 7 8 |
多次元配列は行列の演算や表計算のセル表現のなどの用途で良く使われますが、ジャグ配列の用途がイメージしづらければ、カレンダーを想像するとよいでしょう。 カレンダーでは月ごとに日数が異なりますが、これを表現するのにジャグ配列が使えます。 全12ヶ月をジャグ配列の1段目、各月の日数に応じたデータをジャグ配列の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次元配列を作成しています。
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;
}
}
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次元目を横方向で表しています。
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次元目, … と次元の数だけカンマで区切って長さを指定します。
using System;
class Sample {
static void Main()
{
// 4×2×3個の要素を持つ3次元配列
int[,,] cube = new int[4, 2, 3];
cube[0, 1, 2] = 5;
}
}
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
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;
}
}
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次元配列を作成すると同時に初期化を行っています。
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]);
}
}
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次元配列を図式化すると次のようになります。
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段目と、より高い次元の数列を入れ子の内側に記述します。 次元が高くなる分、記述も複雑になるので注意してください。
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]);
}
}
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
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]);
}
}
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文でインデックスを指定して列挙する必要があります。
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();
}
}
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,
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();
}
}
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,
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();
}
}
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段のジャグ配列を作成しています。
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;
}
}
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段目を横方向で表しています。
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段目][…]
と段数分だけ括弧を連ねて記述します。
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;
}
}
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
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;
}
}
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段のジャグ配列を作成すると同時に初期化を行っています。
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]);
}
}
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段のジャグ配列を図式化すると次のようになります。
jagged[0] → 012 |
jagged[1] → 34 |
jagged[2] → 5678 |
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]);
}
}
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段目の長さを返します。
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);
}
}
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プロパティを個別に参照する必要があります。
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);
}
}
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文を入れ子にしていくことで列挙する必要があります。
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();
}
}
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, ),
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();
}
}
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, ), },
多次元配列のジャグ配列・ジャグ配列の多次元配列・多次元配列の多次元配列
多次元配列の要素の型をジャグ配列にすることにより、ジャグ配列の多次元配列を構築することができます。 また逆に、ジャグ配列の要素の型を多次元配列にすることにより、多次元配列のジャグ配列を構築することもできます。 さらに、多次元配列の多次元配列も構築することができます。
一般に、このようなデータ型が必要になる場合はまれで、必要になったとしてもよりシンプルなデータ型で表現可能である場合がほとんどだと思われます。 以下はあくまでこのようなことも可能ということを示す目的で、多次元配列のジャグ配列・ジャグ配列の多次元配列・多次元配列の多次元配列を構築する例をあげます。
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]);
}
}
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
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]);
}
}
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
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]);
}
}
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です