はじめに
巷で流行っている「成分解析」を作って、乱数の使い方を覚えてみましょう。
対象読者
C#を使ってみたい人、使っている人。
必要な環境
- Windows
- Visual Studio 2005
解説内容
成分解析は、どのような処理を行っているのでしょうか? 『ψ(プサイ)の興味関心空間』によると、乱数を使っているだけのようです。簡単そうです。自分でも作ってみましょう。
作成開始
Visual Studio 2005(以下、VS2005)を起動しましょう。VS2005のExpress版ならば、Microsoftのサイトから無料でダウンロードできます。
[ファイル]メニューの[新規作成]-[プロジェクト]を選んでください。プロジェクトの種類は、Visual C#のWindowsを選び、テンプレートは[Windowsアプリケーション]にします。プロジェクト名は「CZ成分解析」と入力し、[OK]ボタンを押してください。
メイン画面作成
- [表示]メニューから、[ソリューションエクスプローラ]を表示します。
- 最初に表示されるウィンドウは「Form1.cs」で定義されているForm1です。最初に表示されるものなので、「Form1.cs」を「MainForm.cs」に変えてください。クラス名も自動的に変わります。
- [MainForm.cs]をダブルクリックすると、デザイン画面が開きます。タイトルが「Form1」のままなので変更してみましょう。
- [表示]メニューから[プロパティウィンドウ]を表示してください。
Text
プロパティを探して、「Form1」から「成分解析」に変更します。
- [表示]メニューから[ツールボックス]を開きます。完成図のように、テキストボックス(TextBox)とボタン(Button)を配置してください。なお、結果を表示するテキストボックスは、後述のようにプロパティの
Multiline
をtrueにしないと、高さを変更できません。
- 各コントロールの名前を、左上からtbInput、btnAnalyze、tbResultに変更してください。名前は、プロパティの
(Name)
で設定できます。また、それぞれの各プロパティを次のように変更してください。
Anchor
は、画面をリサイズしたときに、コントロールがどのように変わるかを規定します。
ヘルパークラスの作成
2つの要素を持てる汎用の構造体Pair
を作成します。[プロジェクト]メニューの[新しい項目の追加]で[クラス]を選び、ファイル名を「Pair.cs」にして[追加]ボタンを押してください。中身は次のように入力します。
using System; using System.Collections.Generic; namespace CZ成分解析 { /// <summary>ペア</summary> public struct Pair<T, U> { /// <summary>要素1</summary> public T First; /// <summary>要素2</summary> public U Second; /// <summary>コンストラクタ</summary> public Pair(T t) { First = t; Second = default(U); } /// <summary>コンストラクタ</summary> public Pair(T t, U u) { First = t; Second = u; } /// <summary>等値演算</summary> public override bool Equals(object obj) { Pair<T, U> pr = (Pair<T, U>)obj; return First.Equals(pr.First) && Second.Equals(pr.Second); } /// <summary>ハッシュコード</summary> public override int GetHashCode() { return First.GetHashCode() ^ Second.GetHashCode(); } /// <summary>文字列化</summary> public override string ToString() { return First.ToString() + ", " + Second.ToString(); } } }
同様にランダムシャッフル用の「Algo.cs」を次のように作成してください。
using System; using System.Collections.Generic; namespace CZ成分解析 { /// <summary> /// アルゴリズム /// </summary> public static class Algo { /// <summary> /// ランダムシャッフル /// </summary> public static void RandomShuffle<T>(Random r, IList<T> ary) { RandomShuffle(r, ary, 0, ary.Count); } /// <summary> /// ランダムシャッフル /// </summary> public static void RandomShuffle<T> (Random r, IList<T> ary, int s, int e) { for (int i = e - s; i > 1; --i) { int k = r.Next(i); if (k == i - 1) continue; T o = ary[i + s - 1]; ary[i + s - 1] = ary[k + s]; ary[k + s] = o; } } } }
RandomShuffle
はIList<T>
の順番をランダムに変えます。方法は次のとおりです。
- 1番目の要素と1番目以降の要素の中からランダムに選んだ要素を交換します。
- 2番目の要素と2番目以降の要素の中からランダムに選んだ要素を交換します。
- 同様にn-1番目まで続けます。
これにより、すべての順列の数n!通りの中から等確率でランダムな順列を得ることができます。なお、配列の1番目は添え字の0でアクセスするので注意してください。