• C#


    本文通过示例介绍了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>

    参考

  • 相关阅读:
    手游渠道分成的那些坑来等你跳
    [手游新项目历程]-43-sql关键字解决
    一些相似词的区别
    程序员之间的“笑料”
    程序员之间的“笑料”
    2014游戏圈员工跳槽必看
    2014游戏圈员工跳槽必看
    游戏应该怎么做-美术
    游戏应该怎么做-美术
    [手游新项目历程]-44-gdb
  • 原文地址:https://www.cnblogs.com/SouthBegonia/p/12055328.html
Copyright © 2020-2023  润新知