2009年9月9日 星期三

在C#中排序自訂型別陣列(Sorting custom array)

在C#中要對一些基本型態的陣列作排序相當簡單

/// init an integer array
int[] a = { 10, 9, 1, 2, 6, 5, 4 };

/// sort the array
Array.Sort(a);

這樣的方法可以用在已經有實作IComparison的基本型態上
例如int, string, 或是 DateTime...等

如果要針對自訂型態的物件陣列作排序
基本概念就是要能夠比較兩個物件的順序
假設自訂類別如下

public class T1
{
public int index;
public string name;
}

實作有兩種方法,其一就是將該類別實作IComparable
所以需要將類別定義改為

public class T1 : IComparable
{
public int index;
public string name;

/// implement IComparable interface
public int CompareTo(object obj)
{
return this.index - (obj as T1).index;
}
}

實作IComparable實際上需要做的就是CompareTo這個函式
也就是自己與一個傳入的obj比較,然後回傳一個整數
回傳說明
0兩者相等,順序無所謂
正數現在的物件(this)較比較對象(obj)為大,順序在後
負數現在的物件(this)較比較對象(obj)為小,順序在前

這樣實做出來的類別,就可以直接像基本型態一樣直接排序了

private void SortT1(T1[] t)
{
Array.Sort(t);
}

上述的方法有個缺點,排序T1這個類別只能使用一種方法
也就是如果有時候想要依照index排序,而有時又希望可以用name排序的話
就無法用這個方法實現了,這時候我們就要另外實作比較的函式

private int CompareT1ByIndex(T1 t1, T1 t2)
{
return t1.index - t2.index;
}

這個函數和CompareTo的差別就是傳入是兩個T1物件
然後兩者的比較方式和CompareTo是一樣的
之後要做排序的函式就可以改寫成

private void SortT1(T1[] t)
{
Array.Sort(t, CompareT1ByIndex);
}

這樣就可以看出來,如果我們希望使用name來作排序
其實只要另外實作一個CompareT1ByName的函式就可以做到

另外,需要注意的是Array.Sort的實作排序是quick sort,屬於不穩定的排序
所以兩個物件如果相同的話,順序並不一定會依照原本的順序

--
參考資料
Array.Sort(T) 方法 (T[], Comparison(T))
Sorting Arrays [C#]
Array.Sort 泛型方法 (T[])

沒有留言:

張貼留言