コレクション(Collection)





hash


連想配列
Hashtable tbl = new Hashtable (); tbl ["key"] = "value"; // 初期化子リストで生成 Hashtable tbl = new Hashtable(){ {1, "foo"}, {2, "bar"} }; for( DictionaryEntry i in tbl ) { Console.WriteLine( i.Key ); Console.WriteLine( i.Value ); } tbl.Clear();



list


List< Foo > a = new List<Foo> ();


ArrayList


POINT 配列のサイズが動的にかわる場合は ArrayList を使う。
using System.Collections; // リストをつくる。 ArrayList a = new ArrayList(); // リストに要素を追加する。 a.Add( 10 ); // 異なる型のオブジェクトも追加できる。 a.Add( "test" ); // 要素数を取得する a.Count; // 各要素にアクセスする。 generic 型のコンテナのため cast が必要。 int i = a[0]; // すべての要素を削除してリストを空にする。 a.Clear(); // index を指定して削除する a.RemoveAt( 0 ); // 要素を指定して削除する。複数候補があるときは最初にマッチしたものが削除される a.Remove( "test" );



ソート順を操る


POINT Array は動的に 配列サイズを増やすことができない. IComparable は Sort 基準を指定する Interface  .NET Frameworkには、一次元リスト構造でデータを管理する一種の配列である ArrayList クラス(System.Collections.ArrayList)がある。 配列に似ているが、配列では実現できない機能を持っている。 動的にサイズを増加させるというのは、配列ではできないが、ArrayList ならできる。 ArrayList には、Sort という便利なメソッドがある。 問題になるのは、ソートの並び順をどうやって指定するかである。 込み入った自作クラスのインスタンスを詰め込んだArrayListをソートする場合、 どんな基準で並べ替えるべきなのだろうか。 インターフェイス IComparable を実装する、というものだ。 ArrayList に格納するインスタンスが、すべて、このインターフェイスを実装していれば、 これを基準にしてSortメソッドは並べ替えをできる。 IComparable を実装することによって プログラマはソートの並び順を思いどおりにコントロールできる。 using System; using System.Collections; namespace ConsoleApplication100 { // class ClassSample : IComparable { public string number; // 比較するための 基準を実装 public int CompareTo( object obj ) { // Cast OK よ ^ ^/ ( 安全でないけどね. ^ ^/ ) string s = ((ClassSample)obj).number; if( number == "one" && s == "two" ) return -1; if( number == "one" && s == "three" ) return -1; if( number == "two" && s == "one" ) return 1; if( number == "two" && s == "three" ) return -1; if( number == "three" && s == "one" ) return 1; if( number == "three" && s == "two" ) return 1; return 0; } public ClassSample( string s ) { number = s; } } class Class1 { static void Main(string[] args) { ArrayList al = new ArrayList(); // ArrayList.Add() がある. al.Add( new ClassSample("two") ); al.Add( new ClassSample("three") ); al.Add( new ClassSample("one") ); // sort する al.Sort(); foreach( ClassSample cs in al ) { Console.WriteLine( cs.number ); } } } } クラスにIComparableインターフェイスを実装し、CompareToメソッドを記述する。 文字列が英単語の意味順にソートされる。  IComparableは、CompareTo というメソッドを1つだけ持つ。 このメソッドは、自分自身と、引数として渡されたオブジェクトobjを比較して、 小さければ負数、 同じなら0、 大きければ正数を返す。 ここでは文字列one、two、threeを数値の1、2、3に見立てた結果を返している。 もちろん SortメソッドからCompareToメソッドが何度も呼び出されて、 その情報を基準にして並べ替えが行われているのである。 外部から条件を指定してソート  上の例は、ArrayListに格納されるインスタンス自身が、 例えば 住所録なら、名前順でソートしたいときや、住所順でソートしたいときがある。 そういう場合は、ソート順をクラスの外部で指定するという方法もある。 この方法なら、さまざまなソート方法を準備しておき、それを切り替えながら利用できる。
using System.Collections; { // 比較するためのクラスを利用する。 class ClassComparer : IComparer { // 比較の実装 public int Compare( object x, object y ) { double dx = (double)x; double dy = (double)y; return (int)dx - (int)dy; } } class Class1 { static void Main(string[] args) { ArrayList al = new ArrayList(); al.Add( 2.2 ); al.Add( 3.7 ); al.Add( 1.5 ); al.Add( 2.7 ); al.Add( 3.2 ); al.Add( 1.1 ); // すべての要素を削除 al.Clear(); // 要素数 int nr = al.Count; al.Sort( new ClassComparer() ); foreach( double d in al ) { Console.WriteLine( d ); } } } }
2つの値を比較するCompareメソッドだけを記述したクラスを作成すればよい。 このプログラムでは各数値の整数部だけでソートしている。 つまり実数をソートするのだが 順番は整数扱いで決めるというものだ。 小数部は昇順に揃っていないが、整数だけは揃っているという変な状態を作り出している。 さてこれを実現するには、 Sortメソッドの引数にIComparerを渡す。 26行目にその実例が記述されている。 ここではClassComparerクラスのインスタンスが渡されているが、 これにはIComparerが実装されているので、 自動的にそれが取り出されて渡される。  さてIComparerは実装しなければ使えないので、 IComparerを実装するクラスとして、 ClassComparerクラスを定義している。 IComparerは1つのメソッドCompareを含んでいるので、これを実装する。 8行目の引数のx、yは比較すべき2つのオブジェクトである。 これらの値は実数になるはずなので、一度doubleにキャストしてやる。 そして12行目で整数にキャストして比較する。 この比較により、小さければ負数、同じなら0、大きければ正数を返すという条件が満たされる。 Sortメソッド実行時には、何度もCompareメソッドが呼び出され、 その結果により並べ替えが行われる。


Dictionary


DESC キーと値のコレクションを表します。 連想配列のこと。 キー、値ともに、文字列、数値、オブジェクトを利用できる。
{ Dictionary<string,int> bbdic = new Dictionary< string,int >(); // 追加する。 bbdic.Add( "Rooney", 8 ); bbdic["Ronaldo"] = 7; // 既にあるキーはエラーになる。 try { bbdic.Add("Rooney", 18); } catch { Console.WriteLine("Already added . Rooney = {0}", bbdic["Rooney"]); } // キーが無い場合もエラー。 try { Console.WriteLine("Saha = {0}", bbdic["Saha"]); } catch { Console.WriteLine("Not exists Key = Saha ..."); } Console.WriteLine("Dictionaryの内容を表示"); foreach (KeyValuePair<string, int> bx in bbdic) { Console.WriteLine("key = {0}, value = {1}", bx.Key, bx.Value ); } }



IEnumerable インターフェース


POINT IEnumerable インターフェースを利用することで Collection の種類に関係なく同じようにデータを順にとりだすことができる。 逆に Collection というクラスが, 同一の Interface を実装してくれるおかげで 利用する側は同じコードを書くことができる。
int[] a = new int[]{1, 3, 5}; for(int i=0; i<a.Length; ++i) { Console.Write("{0}\n", a[i]); }
// List を使った実装. List list = new List(); list.Add(7); list.Add(5); list.Add(3); list.Add(1); for(Node n=list.head; n!=null; n=n.next) { Console.Write("{0}\n", n.elem); }
コレクションクラスは共通のインターフェースを実装するという決まりを作り、 このインターフェースから要素へのアクセスすることが一般的。 そのためのクラスとして .NET Framework には IEnumerable というインターフェースが用意されている。 C# の配列は IEnumerable インターフェースを実装している。 POINT 実は次のように展開される。
IEnumerator e = array.GetEnumerator(); while(e.MoveNext()) { 型名 変数 = (型名)e.Current; 文 }
// Enumerator 経由で Access する int[] array = new int[]{1, 3, 5, 7}; IEnumerator e = array.GetEnumerator(); while(e.MoveNext()) { int val = (int)e.Current; Console.Write("{0}\n", val); } // foreach 文を利用する. foreach(型名 変数 in コレクション) 文 int[] array = new int[10]{1, 2, 4, 8, 16, 32, 64, 128, 256, 512}; foreach(int n in array) { Console.Write(n + " "); }



Enumerator.を自作する