1. 概要
「C#」は「C++」と似通っているようで、かなり違いますが、配列は特に違いが大きいような気がします。
配列は、クラスでもなく、「namespace」としては、「System」に所属します。
本ページは、下記のサイトを参考にさせていただきました。
「Array.IndexOf メソッド (System)」
「Array.Resize(T[], Int32) メソッド (System)」
「C# - 配列の初期化方法」
「[C#]配列(Array)の要素が何番目かを確認するには?」
「2次元配列いろいろ #初心者」
2. 初期化
「C++」で、やっと覚えた、配列の初期化。
int array[2] = {};
的な、書き方をしますが・・・。
「C#」で、宣言的には、個数を決めずに、スカラ変数の配列を宣言して、0 以外の値で初期化する際は、どうすりゃええんじゃろ?・・・と。
初期化時に、「=」を使わないあたりが、独特でしょうか?
int [] array = new int[] { 1, 2 };
値が、1 と 2 の、配列数 2 の int 型配列が作成されます。
クラスの配列を宣言する場合、「new」で個数を決めていても配列の中身は「null」のままになっています。
特に、クラス内部に存在する場合は、コンストラクタで配列の個数分、「new」してやらないと、「null」のものを扱うことになってしまうので注意が必要です。
例示しますと。
namespace hogehoge
{
[Serializable]
public class classA
{
[Serializable]
public class classB
{
public int c = 0;
public string d = String.Empty;
}
public classB[] b = new classB[10];
public classA() //// コンストラクタ
{
for (int i=0; i<this.b.Length; i++)
{
this.b[i] = new classB();
}
}
}
}
15~21行のコンストラクタで、配列の各要素にインスタンスを作成しているわけです。
スカラ変数のように列挙することもできます。
using System;
public class myClass
{
public int age = 0;
public string name = String.Empty;
}
public class Program
{
static public void Main ()
{
myClass [] myArray = new myClass[]
{
new myClass { age = 20, name = @"hogehoge" },
new myClass { age = 20, name = @"fugafuga" },
new myClass { age = 21, name = @"piyopiyo" },
};
foreach (myClass m in myArray)
{
Console.WriteLine(@"age = [" + m.age + @"] name[" + m.name + @"] index[" + Array.IndexOf(myArray, m) + @"]");
}
}
}
上記のソースで、ロードモジュールを作成して、実行すると下記の結果が得られます。
age = [20] name[hogehoge] index[0]
age = [20] name[fugafuga] index[1]
age = [21] name[piyopiyo] index[2]
3. 多次元配列
多次元配列の書き方は、さらに「C++」と乖離していきます。
「2×3」の配列をとるとき、「C++」では。
int array[2][3];
と書きますが、同じものを「C#」で表現する場合は。
int[,] array = new int[2,3];
または。
int[][] array = new int[2][3];
となります(わたしは、下の書き方の方が好きだな)。
配列の個数を「Length」でとりますが、多次元の場合、これは全ての要素の個数になるようで、それぞれの次元の個数をとるには「GetLength(ネスト)」というメソッドを使用します。
前項の初期化の例で書きますと。
namespace hogehoge
{
[Serializable]
public class classA
{
[Serializable]
public class classB
{
public int c = 0;
public string d = String.Empty;
}
public classB[,] b = new classB[2,3];
public classA() //// コンストラクタ
{
for (int i=0; i<this.b.GetLength(0); i++)
{
for (int j=0; j<this.b.GetLength(1); j++)
{
this.b[i,j] = new classB();
}
}
}
}
}
となります。
面倒なので、多次元配列は、なるべく使わないようにしています。
クラス化して、ネストさせた方が、安心して使えます。
4. 多次元配列の初期化
「[,]」形式の多次元配列の初期化は。
int[,] no = new int[,]{ { 1, 2 } , { 3, 4 }, { 5, 6 } };
と、まぁこれは、素直に理解できます。
「[][]」の形式は、ちょっと面倒で。
int[][] no = new int[][]{ new int[]{ 1, 2 } , new int[]{ 2, 3 }, new int[]{ 4, 5 } };
と、小さい単位の方にも、「new」をつけないと、文法エラーになります。
5. インデックスを求める
クラスの配列で、配列の要素から、インデックスを調べる方法がないものかと調べてみたら、ありました。
Array.IndexOf(配列, 配列の要素)
インデックスは、もちろん、「0」はじまりです。
配列が、「null」の場合は、「ArgumentNullException」の例外が発生しますが、それ以外の例外はないようです。
クラスでなくてもいいようで、スカラ変数で、同じ要素がある場合は、最初に見つかったインデックスが返ります。
検索対象の要素が存在しない場合は、「-1」が返ります。
using System;
public class myClass
{
public int age = 0;
public string name = String.Empty;
}
public class Program
{
static public void Main ()
{
myClass [] myArray = new myClass[]
{
new myClass { age = 20, name = @"hogehoge" },
new myClass { age = 20, name = @"fugafuga" },
new myClass { age = 21, name = @"piyopiyo" },
};
foreach (myClass m in myArray)
{
Console.WriteLine(@"age = [" + m.age + @"] name[" + m.name + @"] index[" + Array.IndexOf(myArray, m) + @"]");
}
}
}
てなソースを書いて、ビルド・実行すると、下記の結果が得られます。
age = [20] name[hogehoge] index[0]
age = [20] name[fugafuga] index[1]
age = [21] name[piyopiyo] index[2]
6. 先頭・末尾
using System.Linq;
を使用することにより、「List」と同様、先頭や末尾の要素を取得できます。
using System;
using System.Linq;
public class Program
{
static public void Main ()
{
int[] array = new int[10];
for (int i=0; i<array.Length; i++)
{
array[i] = i+1;
}
Console.WriteLine("array 先頭["+ array.First() +"]");
Console.WriteLine("array 末尾["+ array.Last() +"]");
}
}
てなソースを書いて、ビルド・実行すると、下記の結果が得られます。
array 先頭[1]
array 末尾[10]
7. リサイズ
「C#」では、配列の個数は、宣言時に変数を使って初期化できるだけでなく、実行時に状況に合わせて、動的にサイズを変えることが可能です。
Array.Resize (ref T[] array, int newSize);
で、第一引数に、配列のリファレンスを渡し、第二引数に個数を設定することで、サイズを変えられます。