SoFunction
Updated on 2025-03-08

--Comprehensive analysis of collection sorting methods in C#

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

Here are 4 ways to customize C# sorting:

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

Achieve the goal

Suppose there is a People class that contains Name and Age attributes. Create List in the client to save multiple instances. You hope to sort the contents in the List according to Name and Age parameters. The sorting rule is to sort first by ascending order by name. If the names are the same, then sort by ascending order of age:

class People
{
 public People(string name, int age) { Name = name; Age = age; }
 public string Name { get; set; } //Name public int Age { get; set; } //age}
 
// Clientclass Client
{
 static void Main(string[] args)
 {
  List&lt;People&gt; peopleList = new List&lt;People&gt;();
  (new People("Zhang San", 22));
  (new People("Zhang San", 24));
  (new People("Li Si", 18));
  (new People("Wang Wu", 16));
  (new People("Wang Wu", 30));
 }
}

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

This method is the system default method, and the default order will be sorted in ascending order by default for a single parameter. However, when encountering multi-parameter (Name, Age) sorting, we need to modify the default method.

Method 1: People class inherits the IComparable interface and implements the CompareTo() method

IComparable<T>: Defines a general comparison method implemented by a value type or class, aiming to create type-specific comparison methods to sort instances.

Principle: The self-implemented CompareTo() method will compare elements in () and finally implement sorting

class People : IComparable&lt;People&gt;
{
 public People(string name, int age) { Name = name;Age = age; }
 public string Name { get; set; }
 public int Age { get; set; }
 
 // () will be customized according to CompareTo() public int CompareTo(People other)
 {
  if ( != )
  {
   return ();
  }
  else if ( != )
  {
   return ();
  }
  else return 0;
 }
}
 
// Client();
 
// OUTPUT:
// Li Si 18// Wang Wu 16// Wang Wu 30// Zhang San 22//  Zhang San 24

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

Different from the above-mentioned method that inherits IComparable, this method cannot inherit and implement the IComparer interface within 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: () Use the instance of PeopleComparer class as a parameter, use the Compare() method internally to compare it in pairs, and finally implement sorting (Note: the above method is CompareTo(), here is the Compare() method)

// Custom comparison method classclass PeopleComparer : IComparer&lt;People&gt;
{
 // Different from CompareTo() single parameter, it is a double parameter here public int Compare(People x, People y)
 {
  if ( != )
  {
   return ();
  }
  else if ( != )
  {
   return ();
  }
  else return 0;
 }
}
 
// Client// Pass the incoming parameter as an instance of the custom comparison class(new PeopleComparer());
 
// OUTPUT:
// Li Si 18// Wang Wu 16// Wang Wu 30// Zhang San 22//  Zhang San 24

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

Method 3: Use generic delegate Comparison<T> to bind custom comparison methods

Different from the above-mentioned inherited interface method, the parameters of this method are Generic Delegation Comparison<T>

Delegate prototype: public delegate int Comparison<in T>(T x, T y);

Method 3: According to the usage method of delegate, first create the delegate instance MyComparison and bind it to the custom comparison method PeopleComparison(). Finally, when the delegate instance is called, the delegate instance is passed in.

Principle: () According to the incoming delegate method, perform two-element comparison and final ordering

// Clientclass Client
{
 // Method 0 Custom comparison method public static int PeopleComparison(People p1, People p2)
 {
  if ( != )
  {
   return ();
  }
  else if ( != )
  {
   return ();
  }
  else return 0;
 }
 
 static void Main(string[] args)
 {
  / createlist ... /
  
  // Method 0 Create a delegate instance and bind  Comparison&lt;People&gt; MyComparison = PeopleComparison;
 
  // Pass in this instance to implement the comparison method  (MyComparison);
 
  // OUTPUT:
  // Li Si 18  // Wang Wu 16  // Wang Wu 30  // Zhang San 22  // Zhang San 24 }
}

In addition, since Comparison<T> is a generic delegate, it can be described with a Lambda expression:

// Lambda expression implements Comparison delegate((p1, p2) =&gt;
{
 if ( != )
 {
  return ();
 }
 else if ( != )
 {
  return ();
 }
 else return 0;
});
 
// OUTPUT:
// Zhang San 24// Zhang San 22// Wang Wu 30// Wang Wu 16//  Li Si 18

Summarize

Although this article only uses List<T> to explain the Sort() method, the methods of using Sort() for different containers are very different, because the core principle is to apply two interfaces and generic delegations:

Two interfaces: IComparable<T>, IComparer<T>

Generic Delegation: Comparison<T>

refer to

IComparable Interface - Microsoft

Comparison Delegation - Microsoft

IComparer Interface - Microsoft

Attachment: A complete test demo

using System;
using ;
using ;
using ; 
namespace ListSort
{
 class Program
 {
  static void DisplayInfo&lt;T&gt;(List&lt;T&gt; list) {
   //Output List element content   foreach(var item in list) {
    ("{0} ",());
   }
   ("");
  }
 
  // Method 3 Custom delegate generic comparison method  public static int PeopleComparison(People p1, People p2)
  {
   if ( != )
   {
    return ();
   }
   else if ( != )
   {
    return ();
   }
   else return 0;
  }
  static void Main(string[] args)
  {
   List&lt;People&gt; peopleList = new List&lt;People&gt;();
   (new People("Zhang San", 22));
   (new People("Zhang San", 24));
   (new People("Li Si", 18));
   (new People("Wang Wu", 16));
   (new People("Wang Wu", 30));
 
   ("Raw data before sorting:");
   DisplayInfo(peopleList);
   ("------------------------------------");
 
   ("Method 1 sorted data:");
   ();
   DisplayInfo(peopleList);
 
   ("Method 2 sorted data:");
   DisplayInfo(peopleList);
 
   // Method 1 Use the IComparer<T> interface.   (new PeopleComparer());
 
   // Method 2 In addition to the above two methods, you can also use another method to implement IComparable<T> in the People class   ();
   ("Method 3 sorted data:");
   DisplayInfo(peopleList);
 
   // Method 3 Create a generic delegate instance and bind it   Comparison&lt;People&gt; MyComparison = PeopleComparison;
 
   // Pass in this instance to implement the comparison method   (MyComparison);
 
   ("Method 3 sorted data:");
   DisplayInfo(peopleList);
 
   // Method 3 Use Comparison<T> delegation, Lambda writing method   ((left, right) =&gt;
   {
    //Sort by name first, if the name is the same, then sort by age    int x = ();
    if(x==0) {
     if ( &gt; )
      x = 1;
     else if ( == )
      x = 0;
     else
      x = -1;
    }
    return x;
   }); 
  }
 }
 
//Method 1 public class People : IComparable&lt;People&gt;
 {
  public int Age { get;set;}
  public string Name { get;set;}
  public People(string name,int age) {
    = name;
    = age;
  }
 
  public override string ToString() {
   string result = "";
   result = "["++","+ ()+"]";
   return result; 
  }
 
  public int CompareTo(People other)
  {
   int x = ();
   if(x==0) {
    if ( &gt; )
     x = 1;
    else if ( == )
     x = 0;
    else
     x = -1;
   }
   return x;
  }
 }
 
 //Method 2 public class PeopleComparer : IComparer&lt;People&gt;
 {
  public int Compare(People left, People right)
  {
   int x = ();
   if(x==0) {
    if ( &gt; )
     x = 1;
    else if ( == )
     x = 0;
    else
     x = -1;
   }
   return x;
  }
 } 
} 

Supplement: C# IComparable and IComparer interfaces and custom comparators

Preface

There is a method in ArrayList:

public virtual void Sort(IComparer comparer);

Use the specified comparator to sort the elements throughout.

comparer: The implementation to be used when comparing elements.

What's the thing?

text

A brief introduction to the class

If you want to figure this out, let’s take a look at this category first.

In the namespace, there is a class: Comparer. As the name suggests, it can achieve comparisons of simple types. What does it mean? Let's see the following code:

int a=1,b=2;

Under normal circumstances, how do we compare their size? if, operator,…? Of course this is OK, but Comparer has provided us with a function that can be used directly: (requires using ;)

((a,b));

Because a<b, the console will output -1. (This function always returns three values ​​-1, 0, and 1.)

Here, the Comparer instance obtained by Default in Comparer is called the non-static function Compare in Comparer.

(You can also compare two string types based on letters, and the introduction will be omitted here)

2. Custom comparator, IComparable, IComparer interface

Of course, this class is not just used to compare the sizes of two numbers. Sometimes we want to directly compare two objects, but referencing attributes may be more troublesome. Especially when there are too many reference elements and it is difficult to compare directly, how can we compare two objects more efficiently? At this time, we need to customize the comparator.

First, let’s introduce the IComparable interface. There is only one method in this interface CompareTo(). Let your class implement the CompareTo method of this interface, and you can directly call this method to compare with another object. Here is an example:

public class ClassTest : IComparable
{
 public int intTest;
 public int CompareTo(object obj)
 {
 return intTest-((ClassTest)obj).intTest;
 //The code here can be written by yourself as needed, here is just a simple example }
}

Then you can use it directly:

ClassTest a = new ClassTest(){intTest=1};
ClassTest b = new ClassTest(){intTest=2};
((b));//Output-1ComparerThe class has been provided for usIComparerThe default implementation of,But we can still customize it。Create a new class:(Rememberusing ;)
public class ClassTestComparer : IComparer
{
 public static IComparer Default = new ClassTestComparer();
 //This definition must be used here. It is of great use to convert objects into IComparer types. The following will introduce public int Compare(object a,object b)
 {
 return ((ClassTest)a).intTest - ((ClassTest)b).intTest;
 // Also the simplest example is used here, but you can shine }
}

Note that if the class used for comparison and the class set is different, an error will occur.

Example of usage:

ClassTest a = new ClassTest(){intTest=1};
ClassTest b = new ClassTest(){intTest=2};
((a,b));
//turn out-1

It can be found that the difference between these two interfaces is that IComparable is implemented in the class of the object to be compared, and that object and another object can be compared. IComparer is implemented in a separate class and can compare any two objects (the key is your settings).

3. Sort the collection

Of course, these two interfaces have more powerful uses. We can use these two interfaces to sort the collection. Do you still remember the Sort() method in the foreword? Next, let’s take ArrayList as an example to introduce how to use it.

ArrayList ClassTests = new ArrayList();
ClassTest a = new ClassTest(){intTest=1};
ClassTest b = new ClassTest(){intTest=2};
ClassTest c = new ClassTest(){intTest=3};
(a);
(b);
(c);
();
//Use Sort without parameters to call the CompareTo() method in the class. Because ClassTest implements this method, it can be called.  If it is not implemented, the compiler will report an error.();
//This will useCompare()Method sorts elements in a collection。ClassTestComparerThe class implements this method,And provide aIComparerProperties of types。

What should be noted is:

The return values ​​of the method provided by both interfaces are of type int, negative numbers represent less than, 0 represents equal, and positive numbers represent greater than. Therefore, for custom comparators outside of numbers, you need to manually set what is "big" and what is "small". Therefore, in the above example, the two numbers are subtracted directly to compare the sizes.

After sorting, the set is arranged from small to large according to the returned int value.

When using Sort() without parameters, at least one class in the collection must implement IComparable, otherwise an error will be reported.

Generally speaking, the same class is compared. However, it is also possible to implement codes that compare different classes, which depends on the specific needs.

The above is personal experience. I hope you can give you a reference and I hope you can support me more. If there are any mistakes or no complete considerations, I would like to give you advice.