C# 经典实例 第一章 类和泛型 #1.2 使类型可排序

问题:

有一种数据类型,它将存储为List<T>或SortedList<K,V>的元素。你想使用List<T>.Sort方法或者SortedList<K,V>的内部排序机制来自定义此数据类型在数组中的排序方式。此外,你可能需要在SortedList集合中使用这种类型。

解决方案:

例1-1演示了如何实现IComparable<T>接口。例1-1中展示的Square类实现了这个接口,使得List<T>和SortedList<K,V>集合能够排序和查找这些Square对象。

例1-1:通过实现IComparable<T> 使类型可排序

using System;

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() => ($"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) => x.Equals(y);
    public static bool operator !=(Square x, Square y) => !(x == y);
    public static bool operator <(Square x, Square y) => (x.CompareTo(y) < 0);
    public static bool operator >(Square x, Square y) => (x.CompareTo(y) > 0);

    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;
    }
}

讨论:

通过在类(或结构)上实现IComparable<T>接口,就可以利用List<T>和SortedList<K,V>类的排序例程。排序算法内置在这些类中。你只需要通过在IComparable<T>.CompareTo方法中实现的代码告诉它如何对你的类进行排序即可。

当调用LIst<Square>.Sort方法对Square对象的列表进行排序时,列表是通过Square对象的Icomparable<Square>接口进行排序的。当把对象添加到SortedList<K,V>中时,SortedList<K,V>类的Add方法使用这个接口对它们进行排序。

IComparer<T>设计用于解决如下问题:运行基于不同环境中的不同标准对对象进行排序。这个接口还允许你对其他人编写的类型进行排序。如果你还想按照高度对Square对象进行排序,就可以创建一个名为CompareHeight的新类,如例1-2中所示。它也实现了IComparer<Square>接口。

例1-2:通过实现Icomparer使类型可排序


using System.Collections.Generic;

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
}

然后将这个类传入Sort方法的Icomparer参数。现在可以指定以不同的方式对Square对象进行排序。比较器中实现的比较方法必须保持一致并应用全局排序,从而使得比较函数声明两个数据项相等时绝对正确,而不是以下情况的结果:一个数据项不大于另一个数据项或者一个数据项不小于另一个数据项。

(注:为了获得最佳性能,需要保持CompareTo方法短小、高效,因为它将被Sort方法调用多次。)

例1-3中展示的TestSort方法演示了如何对List<Square>和SortedList<int,Square>实例使用Square和CompareHeight类。

例1-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) };

        // 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());
        }


        // 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 sing 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

 

参考:

范例1.3(即1.3节);MSDN文档中的”IComparable<T>接口“主题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值