C# List.Sort sorting

In C#, List.Sort() not only provides us with the default sorting method, but also provides us with 4 custom sorting methods. Through the default sorting method, we do not need to rewrite any implementation code of the Sort() method. It can sort the List data of single parameter type with a single rule. If we improve these methods, we can easily achieve complex sorting with multiple parameters and multiple rules.

C# default sorting methods Sort, Reverse

Sort Sort, Reverse Reverse

//默认是元素第一个字母按升序
list.Sort();
//将List里面元素顺序反转
list.Reverse();
//从第二个元素开始,反转4个元素
//结果list里最后的顺序变成"Ha", "Jay", "Lily", "Tom", "Hunter", "Jim", "Kuku",  "Locu"
list.Reverse(1,4);

4 ways to customize sorting in C#

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


To achieve the goal
Suppose there is a People class, including Name and Age attributes, create a List in the client to save multiple instances, and hope to sort the contents of the List according to the Name and Age parameters. The sorting rule is, first sort by name in ascending order, if The names are the same and then sorted in ascending order of 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));
    }
}

Method 1. Inherit the IComparable interface and implement the CompareTo() method

Inherit the IComparable interface for the People class, and implement the CompareTo() method.
This method is the default method of the system. When there is a single parameter, it will be sorted in ascending order by default. But when we encounter multi-parameter (Name, Age) sorting, we need to modify the default method.

Method 1: The People class inherits the IComparable interface and implements the CompareTo() method.
IComparable<T>: Defines a generic comparison method implemented by a value type or class, aiming to create a type-specific comparison method to sort instances.
Principle: The self-implemented CompareTo() method will perform pairwise comparison of elements within list.Sort(), and finally achieve sorting
 

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

Method 2: Add an external comparison class, inherit the IComparer interface, and implement the Compare() method

Add the external comparison class of the People class, inherit the IComparer interface, and implement the Compare() method.
Different from the above method of inheriting IComparable, this method cannot inherit and implement the IComparer interface in People, but requires a new comparison method class to implement the interface.

Method 2: Create a new PeopleComparer class, inherit the IComparer interface, and implement the Compare() method
Principle: list.Sort() takes the instance of the PeopleComparer class as a parameter, and uses the Compare() method internally to perform pairwise comparisons, and finally achieve sorting (Note: the above The method is CompareTo(), here is the Compare() method)
 

// 自定义比较方法类
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

Similarly, the parameters of the List<T>.Sort(int index, int count, IComparer<T> Comparer) method: the starting index of the elements to be sorted, the number of elements to be sorted, and the sorting method

Method 3. Use generic delegate Comparison<T> to bind a custom comparison method


Different from the above methods of inheriting the interface, the parameter of this method is the generic delegate Comparison<T>

Delegate prototype: public delegate int Comparison<in T>(T x, T y);
Method 3: According to the usage method of the delegate, first create the delegate instance MyComparison, bind it to the custom comparison method PeopleComparison(), and finally call When list.Sort(), the delegate instance is passed in
Principle: list.Sort() compares the two elements according to the incoming delegate method, and finally realizes the sorting
 

// 客户端
class Client
{
    // 方法0 自定义比较方法
    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 ... /
        
        // 方法0 创建委托实例并绑定
        Comparison<People> MyComparison = PeopleComparison;
 
        // 传入该实例实现比较方法
        peopleList.Sort(MyComparison);
 
        // OUTPUT:
        //      李四 18
        //      王五 16
        //      王五 30
        //      张三 22
        //      张三 24
    }
}

Generic Delegate with  Lambda Expression

In addition, since it Comparison<T>is a generic delegate, it can be completely described by  Lambda expressions  :

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

Summarize


Although this article only uses List<T> as a container to describe the Sort() method, the methods of using Sort() for different containers are quite different, because the core principle is to apply two interfaces and generic delegates:

Two Interfaces: IComparable<T>, IComparer<T>
Generic Delegate: Comparison<T>
Reference
IComparable Interface - Microsoft  IComparable
Comparison Delegate - Microsoft  Comparison
IComparer Interface - Microsoft  IComparer Interface (System.Collections) | Microsoft Docs
IComparable and IComparer Interface And custom comparator - My_Pure  C# IComparable and IComparer interface and custom comparator - short book


  Attachment: A complete test Demo

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
  
namespace ListSort
{
    class Program
    {
        static void DisplayInfo<T>(List<T> list) {
            //输出List元素内容
            foreach(var item in list) {
                System.Console.Write("{0} ",item.ToString());
            }
            System.Console.WriteLine("");
        }
 
        // 方法3 自定义委托泛型比较方法
        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<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));
 
            System.Console.WriteLine("排序前原始数据:");
            DisplayInfo(peopleList);
            System.Console.WriteLine("------------------------------------");
 
            System.Console.WriteLine("方法1排序后数据:");
            peopleList.Sort();
            DisplayInfo(peopleList);
 
            System.Console.WriteLine("方法2排序后数据:");
            DisplayInfo(peopleList);
 
            // 方法1 使用IComparer<T>接口。
            peopleList.Sort(new PeopleComparer());
  
            // 方法2 除以上两种方法以外还可以使用另一种方法,在People类中实现IComparable<T>
            peopleList.Sort();
            System.Console.WriteLine("方法3排序后数据:");
            DisplayInfo(peopleList);
 
            // 方法3 创建泛型委托实例并绑定
            Comparison<People> MyComparison = PeopleComparison;
 
            // 传入该实例实现比较方法
            peopleList.Sort(MyComparison);
 
            System.Console.WriteLine("方法3排序后数据:");
            DisplayInfo(peopleList);
 
            // 方法3 使用Comparison<T>委托,Lambda写法
            peopleList.Sort((left, right) =>
            {
                //先按姓名排序,如果姓名相同再按年龄排序
                int x = left.Name.CompareTo(right.Name);
                if(x==0) {
                    if (left.Age > right.Age)
                        x = 1;
                    else if (left.Age == right.Age)
                        x = 0;
                    else
                        x = -1;
                }
                return x;
            });
  
        }
    }
 
  //方法一
    public class People : IComparable<People>
    {
        public int Age { get;set;}
        public string Name { get;set;}
        public People(string name,int age) {
            this.Name = name;
            this.Age = age;
        }
 
        public override string ToString() {
            string result = "";
            result = "["+this.Name+","+ this.Age.ToString()+"]";
            return result;
 
        }
 
        public int CompareTo(People other)
        {
            int x = this.Name.CompareTo(other.Name);
            if(x==0) {
                if (this.Age > other.Age)
                    x = 1;
                else if (this.Age == other.Age)
                    x = 0;
                else
                    x = -1;
            }
            return x;
        }
    }
 
   //方法二
   public class PeopleComparer : IComparer<People>
   {
       public int Compare(People left, People right)
       {
            int x = left.Name.CompareTo(right.Name);
            if(x==0) {
                if (left.Age > right.Age)
                    x = 1;
                else if (left.Age == right.Age)
                    x = 0;
                else
                    x = -1;
            }
            return x;
       }
   }
 
}   

Guess you like

Origin blog.csdn.net/qq_42672770/article/details/123344526