■ 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.を自作する