C# - List.Sort()自定義排序方法


本文通過示例介紹了C#中典型容器List.Sort()的自定義排序方法,進而引出了C#中自定義排序的核心接口及方法

項目地址:自定義Sort方法 - SouthBegonia's Github

List.Sort() 為我們提供了4種自定義排序方法,通過對這些方法改進我們可以輕松做到對多參數、多規則的復雜排序:

List<T>.Sort();
List<T>.Sort(IComparer<T> Comparer);
List<T>.Sort(int index, int count, IComparer<T> Comparer);
List<T>.Sort(Comparison<T> comparison);

項目背景

存在People類,包含Name、Age屬性,在客戶端中創建List 保存多個實例,對List 根據Name和Age參數進行排序:

class People
{
    public People(string name, int age) { Name = name; Age = age; }
    public string Name { get; set; }
    public int Age { get; set; }
}

// 客戶端
class Client
{
	static void Main(string[] args)
	{
	    List<People> peopleList = new List<People>();
	    peopleList.Add(new People("張三", 22));
	    peopleList.Add(new People("張三", 24));
	    peopleList.Add(new People("李四", 18));
	    peopleList.Add(new People("王五", 16));
	    peopleList.Add(new People("王五", 30));
	}
}

List .Sort()

該方法為系統默認的方法,單一參數時會默認進行升序排序。但遇到多參數(Name、Age)排序時,我們需要對該默認方法進行修改。

  • 方法:People類繼承IComparable ,實現CompareTo()方法
  • IComparable<T>:定義由值類型或類實現的通用比較方法,旨在創建特定於類型的比較方法以對實例進行排序。
  • 原理:自行實現的CompareTo()方法會在list.Sort()內部進行元素兩兩比較,最終實現排序
class People : IComparable<People>
{
    public People(string name, int age) { Name = name;Age = age; }
    public string Name { get; set; }
    public int Age { get; set; }

	// list.Sort()時會根據該CompareTo()進行自定義比較
    public int CompareTo(People other)
    {
        if (this.Name != other.Name)
        {
            return this.Name.CompareTo(other.Name);
        }
        else if (this.Age != other.Age)
        {
            return this.Age.CompareTo(other.Age);
        }
        else return 0;
    }
}

// 客戶端
peopleList.Sort();

// OUTPUT:
//      李四 18
//      王五 16
//      王五 30
//      張三 22
//      張三 24

List .Sort(IComparer Comparer)

區別於上述繼承IComparable 的方法,該方法 不可在People內繼承實現IComparer 接口,而是需要 新建比較方法類進行接口實現

  • 方法:新建PeopleComparer類、繼承IComparer 接口、實現Compare()方法
  • 原理:list.Sort()將PeopleComparer類的實例作為參數,在內部使用Compare()方法進行兩兩比較,最終實現排序(注:上述方法為CompareTo(),此處為Compare()方法)
// 自定義比較方法類
class PeopleComparer : IComparer<People>
{
	// 區別於CompareTo()單參數,此處為雙參數
    public int Compare(People x, People y)
    {
        if (x.Name != y.Name)
        {
            return x.Name.CompareTo(y.Name);
        }
        else if (x.Age != y.Age)
        {
            return x.Age.CompareTo(y.Age);
        }
        else return 0;
    }
}

// 客戶端
// 傳入參數為自定義比較類的實例            
peopleList.Sort(new PeopleComparer());

// OUTPUT:
//      李四 18
//      王五 16
//      王五 30
//      張三 22
//      張三 24

同理,List<T>.Sort(int index, int count, IComparer<T> Comparer) 方法的參數:待排元素起始索引、待排元素個數、排序方法

List .Sort(Comparison comparison)

區別於上述繼承接口的方法,此方法的參數為 泛型委托 Comparison<T>

  • 委托原型:public delegate int Comparison<in T>(T x, T y);
  • 方法:依照委托的使用方法,首先創建委托實例MyComparison,並綁定到自定義的比較方法PeopleComparison()上,最終調用list.Sort()時 將委托實例傳入
  • 原理:list.Sort()根據傳入的委托方法,進行兩兩元素比較最終實現排序
// 客戶端
class Client
{
	// 自定義比較方法
    public static int PeopleComparison(People p1, People p2)
    {
        if (p1.Name != p2.Name)
        {
            return p1.Name.CompareTo(p2.Name);
        }
        else if (p1.Age != p2.Age)
        {
            return p1.Age.CompareTo(p2.Age);
        }
        else return 0;
    }

	static void Main(string[] args)
	{
		/* 創建list ... */
		
		// 創建委托實例並綁定
        Comparison<People> MyComparison = PeopleComparison;

		// 傳入該實例實現比較方法
        peopleList.Sort(MyComparison);

        // OUTPUT:
        //      李四 18
        //      王五 16
        //      王五 30
        //      張三 22
        //      張三 24
	}
}

此外,既然Comparison<T>是泛型委托,則完全可以用 Lambda表達式 進行描述:

// Lambda表達式實現Comparison委托
peopleList.Sort((p1, p2) =>
{
    if (p1.Name != p2.Name)
    {
        return p2.Name.CompareTo(p1.Name);
    }
    else if (p1.Age != p2.Age)
    {
        return p2.Age.CompareTo(p1.Age);
    }
    else return 0;
});

// OUTPUT:
//      張三 24
//      張三 22
//      王五 30
//      王五 16
//      李四 18

總結

雖然本文僅使用了List<T>一種容器對Sort()方法進行闡述,但是不同容器的使用Sort()的方法大相徑庭,因為核心的原理都是應用兩種接口及泛型委托

  • 兩種接口IComparable<T> 、 IComparer<T>
  • 泛型委托Comparison<T>

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM