C# 3.0 CookBook:三、类与结构(2):类型支持排序

问题

   要使自定义类型能够像一个List<T>或SortedList<K,V>结构那样可排序。一般情况下,我们会倾向于使用List<T>.Sort方法或SortedList<K,V>的内部排序机制,来定制由用户自定义数据类型组成的数组中的排序规则。此外,用户可能需要在SortedList集合中使用此类型。

解决方案

    例3-1示范了怎样实现IComparable<T>接口。例3-1中的Square类实现了该接口使其能够像List<T>和SortedList<K,V>集合那样对Square对象进行排序和搜索。

//示例3-1.实现IComparable<T>接口,让类型可以排序
public class Square : IComparable<Square>
{
    public Square() { }
    public Square(int height, int width)
    {
        this.Height = height;
        this.Width = width;
    }
    public int Height { get; set; }
    public int Width { get; set; }
    public int CompareTo(object obj)
    {
        Square square = obj as Square;
        if (square != null)
            return CompareTo(square);
        throw
        new ArgumentException("Both objects being compared must be of type Square.");
    }
    public override string ToString()
    {
        return ("Height:" + this.Height + " Width:" + this.Width);
    }
    public override bool Equals(object obj)
    {
        if (obj == null)
            return false;
        Square square = obj as Square;
        if (square != null)
            return this.Height == square.Height;
        return false;
    }
    public override int GetHashCode()
    {
        return this.Height.GetHashCode() | this.Width.GetHashCode();
    }
    public static bool operator ==(Square x, Square y)
    {
        return x.Equals(y);
    }
    public static bool operator !=(Square x, Square y)
    {
        return !(x == y);
    }
    public static bool operator <(Square x, Square y)
    {
        return (x.CompareTo(y) < 0);
    }
    public static bool operator >(Square x, Square y)
    {
        return (x.CompareTo(y) > 0);
    }
    #region IComparable<Square> Members
    public int CompareTo(Square other)
    {
        long area1 = this.Height * this.Width;
        long area2 = other.Height * other.Width;
        if (area1 == area2)
            return 0;
        else if (area1 > area2)
            return 1;
        else if (area1 < area2)
            return -1;
        else
            return -1;
    }
    #endregion
}

讨论

    依靠在自定义类型(或结构)中实现IComparable<T>接口,可以得到List<T>和SortedList<K,V>类一样的排序算法的性能优势。排序算法内置在这些类定义中,用户需要做的就是实现IComparable<T>.CompareTo方法,通过代码告诉他们怎样对用户自定义的类进行排序。

//示例3-2. 实现IComparable<T>接口,让类型可以排序
public class CompareHeight : IComparer<Square>
{
    public int Compare(object firstSquare, object secondSquare)
    {
        Square square1 = firstSquare as Square;
        Square square2 = secondSquare as Square;
        if (square1 == null || square2 == null)
            throw (new ArgumentException("Both parameters must be of type Square."));
        else
            return Compare(firstSquare, secondSquare);
    }
    #region IComparer<Square> Members
    public int Compare(Square x, Square y)
    {
        if (x.Height == y.Height)
            return 0;
        else if (x.Height > y.Height)
            return 1;
        else if (x.Height < y.Height)
            return -1;
        else
            return -1;
    }
    #endregion
}

    当调用List<Square>.Sort方法对一个Square对象的列表进行排序时,该列表使用Square对象的IComparable<Square>接口来实现排序。当它们被添加到SortedList<K,V>中时,SortedList<K,V>的Add方法使用该接口对上述对象进行排序。

    设计IComparer<T>接口是用于解决在不同的上下文关系(不同的自定义类型)中以不同的标准排序的问题。这些接口也可以使用户对那些没有实现的类排序。如果想按照宽度对Square对象排序,那么要创建一个名叫CompareHeight的新类型,同样也要实现IComparer<Square>接口,如示例3-2所示:

    当该类传入Sort方法的IComparer参数时,用户可指定不同的规则对Square对象排序。完成的比较方法必须是一致的和全序的,所以当比较函数比较两个对象是否相等时,当一个对象不大于或不小于另一个对象时,将返回绝对真和假的结果。

提示 为了最好的表现效果,保持CompareTo方法的简洁,因为该方法会被Sort方法调用多次。例如,对一个拥有4个对象的数组排序,Compare方法将被调用10次。

    示例3-3的TestSort方法演示了在Square类和CompareHeight类中怎样使用List<Square> 和SortedList<int,Square>实例。

//示例3-3. TestSort方法
public static void TestSort()
{
    List<Square> listOfSquares = new List<Square>(){
                                        new Square(1,3),
                                        new Square(4,3),
                                        new Square(2,1),
                                        new Square(6,1)};
    // Test a List<String>
    Console.WriteLine("List<String>");
    Console.WriteLine("Original list");
    foreach (Square square in listOfSquares)
    {
        Console.WriteLine(square.ToString());
    }
    Console.WriteLine();
    IComparer<Square> heightCompare = new CompareHeight();
    listOfSquares.Sort(heightCompare);
    Console.WriteLine("Sorted list using IComparer<Square>=heightCompare");
    foreach (Square square in listOfSquares)
    {
        Console.WriteLine(square.ToString());
    }
    Console.WriteLine();
    Console.WriteLine("Sorted list using IComparable<Square>");
    listOfSquares.Sort();
    foreach (Square square in listOfSquares)
    {
        Console.WriteLine(square.ToString());
    }
    // Test a SORTEDLIST
    var sortedListOfSquares = new SortedList<int, Square>(){
                                        { 0, new Square(1,3)},
                                        { 2, new Square(3,3)},
                                        { 1, new Square(2,1)},
                                        { 3, new Square(6,1)}};
    Console.WriteLine();
    Console.WriteLine();
    Console.WriteLine("SortedList<Square>");
    foreach (KeyValuePair<int, Square> kvp in sortedListOfSquares)
    {
        Console.WriteLine(kvp.Key + " : " + kvp.Value);
    }
}
    上述代码的输出结果如下所示:

List<String>
Original list
Height:1 Width:3
Height:4 Width:3
Height:2 Width:1
Height:6 Width:1
Sorted list using IComparer<Square>=heightCompare
Height:1 Width:3
Height:2 Width:1
Height:4 Width:3
Height:6 Width:1
Sorted list using IComparable<Square>
Height:2 Width:1
Height:1 Width:3
Height:6 Width:1
Height:4 Width:3
SortedList<Square>
0 : Height:1 Width:3
1 : Height:2 Width:1
2 : Height:3 Width:3
3 : Height:6 Width:1

还可参见

    条目3.3;还有MSDN文档中的“IComparable<T>接口”主题。

版权说明:作者:张颖希PocketZ's Blog
出处:http://www.cnblogs.com/PocketZ
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

本文翻译内容取自网络,纯粹是练习英文水平,如有雷同,纯属意外!有不妥之处,欢迎拍砖!

posted @ 2010-04-24 20:30  pocketz  阅读(604)  评论(0编辑  收藏  举报