討論一下C#面向集合的擴展
我們知道有很多數學軟件,如MatLab是面向矩陣的,而開源語言R是面向向量的,SQL是面向關系系的、APL(Array processing language)是一種一種多用途、第三代(3GL)編程語言,在向量、矩陣等各種秩的數組處理上非常簡單。SPSS,SAS等都需要大量的集合運算。
本文試圖從C#本身的特性出發,模擬C#面向集合的方法。
更期望C#面向集合能向MatLab, APL,R那樣直接處理集合運算,進入科學和工程計算領域,為以后的并行計算奠定基礎。
有一列觀測值,用List存儲,我們現在需要求出每一個觀測值的正弦Sin值。
用C#面向過程的語法表示如下:
- List list2;
- for (int i = 0; i < list2.Count; i++)
- list2[i] = Math.Sin(list2[i]);
求Sin值,是一個繁瑣而又重復的問題。我們希望Math.Sin(Collection c),在不改變已有代碼(不擴展Math.Sin)的情況下,自動處理集合,就像在MatLab里面。
C#是面向過程的,而Matlab是面向矩陣的,SQL是面向關系代數的。關系代數和矩陣,都可以看作集合的特例。(LINQ部分加入了面向集合的特性)
面向過程,需要程序員書寫算法的每一個過程和細節,指明執行路徑,這主要表現在循環語句的使用上(包括for, foreach, while…)。
面向過程給了程序員最充分的自由和最大的靈活,但其固有的“底層”,導致了開發效率的底下,同時不利于并行計算和系統優化。而在數學中,大部分計算都是基于矩陣(集合),例如圖形圖像處理,概率論,數理統計,優化控制等等。 所以C#難以勝任運算集中和知識處理,人工智能設計。
由于C#實在是太優美,是目前最藝術的語言,利用C#現有特性,我們可以簡單的模擬前面提出的問題
- public static List Apply(Converter f, List l)
- {
- List list2 = new List(l);
- for (int i = 0; i < list2.Count; i++)
- list2[i] = Math.Sin(list2[i]);
- for (int i = 0; i < l.Count; i++)
- {
- list2[i] = f(l[i]);
- }
- return list2;
- }
這樣,我們可以在Apply來處理一些關于集合處理的問題。
下面在給出一個處理矩陣的例子:
- public static Matrix Apply(Converter f, Matrix m)
- {
- Matrix m2 = new Matrix(m);
- for (int i = 0; i < m.Row; i++)
- for (int j = 0; j < m.Col; j++)
- m2[i, j] = f(m2[i, j]);
- return m2;
- }
使用這個Apply,可以處理矩陣集合相關的計算。
矩陣定義如下:
- public class Matrix
- {
- public double[,] data;
- public Matrix(int row, int col)
- {
- data = new double[row, col];
- }
- //復制構造函數
- public Matrix(Matrix m)
- {
- data = (double[,])m.data.Clone();
- }
- public int Col
- {
- get
- {
- return data.GetLength(1);
- }
- }
- // 行數
- public int Row
- {
- get
- {
- return data.GetLength(0);
- }
- }
- //重載索引
- //存取數據成員
- public virtual double this[int row, int col]
- {
- get
- {
- return data[row, col];
- }
- set
- {
- data[row, col] = value;
- }
- }
- //維數
- public int Dimension
- {
- get { return 2; }
- }
- public string ToString(int prec)
- {
- StringBuilder sb = new StringBuilder();
- string format = "{0:F" + prec.ToString() + "} ";
- for (int i = 0; i < Row; i++)
- {
- for (int j = 0; j < Col - 1; j++)
- {
- sb.Append(string.Format(format, data[i, j]));
- }
- sb.Append(data[i, Col - 1]);
- sb.Append(""n");
- }
- return sb.ToString();
- }
- }
再看下面復數的例子:
- public static List Apply(Converter< Complex,double> f, List l)
- {
- List l2 = new List(l.Count);
- for (int i = 0; i < l.Count; i++)
- l2.Add(f(l[i]));
- return l2;
- }
使用這個Apply,可以處理復數集合相關的許多計算。
復數類的定義如下:
- Code
- public class Complex:ICloneable
- {
- private double real;
- /**////
- /// 復數的實部
- ///
- public double Real
- {
- get { return real; }
- set { real = value; }
- }
- private double image;
- /**////
- /// 復數的虛部
- ///
- public double Image
- {
- get { return image; }
- set { image = value; }
- }
- /**////
- /// 默認構造函數
- ///
- public Complex()
- : this(0, 0)
- {
- }
- /**////
- /// 只有實部的構造函數
- ///
- /// 實部
- public Complex(double real)
- : this(real, 0) { }
- /**////
- /// 由實部和虛部構造
- ///
- /// 實部
- /// 虛部
- public Complex(double r, double i)
- {
- rreal = r;
- iimage = i;
- }
- /**////重載加法
- public static Complex operator +(Complex c1, Complex c2)
- {
- return new Complex(c1.real + c2.real, c1.image + c2.image);
- }
- /**////重載減法
- public static Complex operator -(Complex c1, Complex c2)
- {
- return new Complex(c1.real - c2.real, c1.image - c2.image);
- }
- /**////重載乘法
- public static Complex operator *(Complex c1, Complex c2)
- {
- return new Complex(c1.real * c2.real - c1.image * c2.image, c1.image * c2.real + c1.real * c2.image);
- }
- /**////
- /// 求復數的模
- ///
- /// 模
- public double Modul
- {
- get
- {
- return Math.Sqrt(real * real + image * image);
- }
- }
- public static double Sin(Complex c)
- {
- return c.image / c.Modul;
- }
- /**////
- /// 重載ToString方法
- ///
- /// 打印字符串
- public override string ToString()
- {
- if (Real == 0 && Image == 0)
- {
- return string.Format("{0}", 0);
- }
- if (Real == 0 && (Image != 1 && Image != -1))
- {
- return string.Format("{0} i", Image);
- }
- if (Image == 0)
- {
- return string.Format("{0}", Real);
- }
- if (Image == 1)
- {
- return string.Format("i");
- }
- if (Image == -1)
- {
- return string.Format("- i");
- }
- if (Image < 0)
- {
- return string.Format("{0} - {1} i", Real, -Image);
- }
- return string.Format("{0} + {1} i", Real, Image);
- }
- ICloneable 成員#region ICloneable 成員
- public object Clone()
- {
- Complex c = new Complex(real, image);
- return c;
- }
- #endregion
- }
從前面三個例子,我們可以看出,C#面向集合有多種表示方式,有.net框架中的List,也有自定義的Matrix,同時集合的元素也是多種數據類型,有系統中的值類型,也有自定義的復數Complex類型。
當然這種算法過于勉強,顯然不是我們所需要的。
我們需要的是一個在不更改現有語言的情況下,不擴充Math.Sin函數(試著想想有多少個類似的函數,Cos, Tan, 我們自己定義的各種函數)。系統自動處理集合。也就是說,對于函數 public delegate TOutput Converter
【編輯推薦】