Sorting a List of Complex Type in C#

Introduction

.Net provides a method sort() for sorting a list that contains a primitive data type, but for a list that contains a complex data type, the sort() method is not working.In the blog post, we will see how to sort a list containing complex data types.

Getting Started

The sort method of generic collection in .Net works for a list that contains primitive or simple data types, it is very straightforward to invoke the Sort() method on the list instance and the data will be automatically sorted in ascending order.

Sorting List of Primitive Types

For example, if a list has data type int, double string or char, etc. then that list can be sorted by invoking the sort() method directly on the instance. the following code examples describe how to use the sort() method with a list of simple types.

List of Integer

The following source code sorts an integer list and displays the result in the console window.

 List<int> list = new List<int> { 5, 7, 3, 8, 9, 4, 2, 1, 6 };  
 list.Sort();  
 Console.WriteLine("Result after sorting");  
 foreach (int x in list)  
 {  
   Console.WriteLine(x);  
 }  
Result
 Result after sorting  
 1  
 2  
 3  
 4  
 5  
 6  
 7  
 8  
 9  

List of String

The following source code sorts a string list and displays the result in the console window.

 List<string> stringList = new List<string>() { "Raman", "Krishna", "Shyam", "Baishnav", "Asutosh" };  
 stringList.Sort();  
 Console.WriteLine("Result after sorting");  
 foreach (string s in stringList)  
 {  
      Console.WriteLine(s);  
 }  
Result
 Result after sorting  
 Asutosh  
 Baishnav  
 Krishna  
 Raman  
 Shyam  

But in the case of a complex type list is not straightforward. if the sort() method is invoked on the instance of a complex type list then in run time throw “Invalid operation exception – Failed to compare two elements in the array“because it does not understand how would sort the list.

For example, if a list contains a collection of class objects if we invoke the sort() method on the instance of the list then the run time will throw the above-mentioned exception because the run does not understand whether comparison would apply on the instance of the class or to the properties of the class object.

Use the following code example to demonstrate how the sort method throws an exception.

 List<Student> students = new List<Student>();  
 students.Add(new Student { ID = 1, Name = "Rajesh", Class = 1, Mark = 89 });  
 students.Add(new Student { ID = 2, Name = "Ravindar", Class = 3, Mark = 98 });  
 students.Add(new Student { ID = 3, Name = "Yoshna", Class = 2, Mark = 79 });  
 students.Sort();  
Result
Sort a List in C#

Sorting A List


In the above case, the .NET Runtime did not identify whether to sort the data based on ID, Name, or Class, or based on Mark property, or a combination of any properties.

Solution of Sorting A List

To sort out this problem the .Net Framework introduced the IComparable Interface where we can explicitly mention to which property the run time will compare.

IComparable Interface

IComparable interface defines a generalized type-specific comparison method that a value type or class implements to order or sort its instances.

The following code example illustrates to use the IComparable interface and sort the list by comparing the Mark property.

 class Program  
   {  
     static void Main(string[] args)  
     {  
       try  
       {  
         List<Student> students = new List<Student>();  
         students.Add(new Student { ID = 1, Name = "Rajesh", Class = 1, Mark = 89 });  
         students.Add(new Student { ID = 2, Name = "Ravindar", Class = 3, Mark = 98 });  
         students.Add(new Student { ID = 3, Name = "Yoshna", Class = 2, Mark = 79 });  
         Console.WriteLine("Student details before sorting");  
         foreach(Student s in students)  
         {  
           Console.WriteLine("ID :{0}, Name:{1}, Class: {2}, Mark:{3}", s.ID, s.Name, s.Class, s.Mark);   
         }  
         Console.WriteLine();  
         students.Sort();  
         Console.WriteLine("Student details after sorting");  
         foreach (Student s in students)  
         {  
           Console.WriteLine("ID :{0}, Name:{1}, Class: {2}, Mark:{3}", s.ID, s.Name, s.Class, s.Mark);  
         }  
       }  
       catch (Exception ex)  
       {  
         Console.WriteLine(ex.Message);  
       }  
       Console.ReadLine();  
     }  
     public class Student : IComparable<Student>  
     {  
       public int ID { get; set; }  
       public string Name { get; set; }  
       public int Class { get; set; }  
       public float Mark { get; set; }  
       public int CompareTo(Student other)  
       {  
         return this.Mark.CompareTo(other.Mark);  
       }  
     }  
   }  
Result
 Student details before sorting  
 ID :1, Name:Rajesh, Class: 1, Mark:89  
 ID :2, Name:Ravindar, Class: 3, Mark:98  
 ID :3, Name:Yoshna, Class: 2, Mark:79  
 Student details after sorting  
 ID :3, Name:Yoshna, Class: 2, Mark:79  
 ID :1, Name:Rajesh, Class: 1, Mark:89  
 ID :2, Name:Ravindar, Class: 3, Mark:98  

In the CompareTo function you can compare any properties of complex type and own logic can be writen to provide ordering of your class on several fields or properties, ascending and descending order on the same field, or both like below.

Ascending Order

 public int CompareTo(Student other)  
 {  
      if (this.Mark > other.Mark)  
           return 1;  
      if (this.Mark < other.Mark)  
           return -1;  
      else  
           return 0;  
 }  

Descending Order

 public int CompareTo(Student other)  
 {  
      if (this.Mark < other.Mark)  
           return 1;  
      if (this.Mark > other.Mark)  
           return -1;  
      else  
           return 0;  
 }  
Problem:-

Problem with the IComparable Interface is that you can implement the IComparable interface when you have access of the Student class to modify it. Asume that you have provided a library that is built by third pary and the student class is inside the library. In this case you don't have access to the class to modify then how will sort a list that you created using the student class.

To overcome this .Net Framework provides another interface that is call IComparer Interface which provides that capability by requiring a class to provide Compare() method. Where you can create you own class by implementing the IComparer interface and use it to sort a list of complex class. See the blow code example to know more it.

IComparer Interface

The following example demonstrates the use of the IComparer interface to sort a list. In this example, the Compare method is implemented using the AscendingOrderHelper class to order the list in asending order and DescendingHelper class to reverse the order of the contents of the List.

 class Program  
   {  
     static void Main(string[] args)  
     {  
       try  
       {  
         List<Student> students = new List<Student>();  
         students.Add(new Student { ID = 1, Name = "Rajesh", Class = 1, Mark = 89 });  
         students.Add(new Student { ID = 2, Name = "Ravindar", Class = 3, Mark = 98 });  
         students.Add(new Student { ID = 3, Name = "Yoshna", Class = 2, Mark = 79 });  
         Console.WriteLine("Student details before sorting");  
         foreach(Student s in students)  
         {  
           Console.WriteLine("ID :{0}, Name:{1}, Class: {2}, Mark:{3}", s.ID, s.Name, s.Class, s.Mark);   
         }  
         Console.WriteLine();  
         AscendingOrderHelper ascendingOrder = new AscendingOrderHelper();  
         students.Sort(ascendingOrder);  
         Console.WriteLine("Student details after sorting for ascending order");  
         foreach (Student s in students)  
         {  
           Console.WriteLine("ID :{0}, Name:{1}, Class: {2}, Mark:{3}", s.ID, s.Name, s.Class, s.Mark);  
         }  
         Console.WriteLine();  
         DescendingOrderHelper descendingOrder = new DescendingOrderHelper();  
         students.Sort(descendingOrder);  
         Console.WriteLine("Student details after sorting for descending order");  
         foreach (Student s in students)  
         {  
           Console.WriteLine("ID :{0}, Name:{1}, Class: {2}, Mark:{3}", s.ID, s.Name, s.Class, s.Mark);  
         }  
       }  
       catch (Exception ex)  
       {  
         Console.WriteLine(ex.Message);  
       }  
       Console.ReadLine();  
     }  
     public class AscendingOrderHelper : IComparer<Student>  
     {  
       public int Compare(Student x, Student y)  
       {  
         if (x.Mark > y.Mark)  
           return 1;  
         if (x.Mark < y.Mark)  
           return -1;  
         else  
           return 0;  
       }  
     }  
     public class DescendingOrderHelper : IComparer<Student>  
     {  
       public int Compare(Student x, Student y)  
       {  
         if (x.Mark < y.Mark)  
           return 1;  
         if (x.Mark > y.Mark)  
           return -1;  
         else  
           return 0;  
       }  
     }  
     public class Student  
     {  
       public int ID { get; set; }  
       public string Name { get; set; }  
       public int Class { get; set; }  
       public float Mark { get; set; }  
     }  
   }  
Result
 Student details before sorting  
 ID :1, Name:Rajesh, Class: 1, Mark:89  
 ID :2, Name:Ravindar, Class: 3, Mark:98  
 ID :3, Name:Yoshna, Class: 2, Mark:79  
 Student details after sorting for ascending order  
 ID :3, Name:Yoshna, Class: 2, Mark:79  
 ID :1, Name:Rajesh, Class: 1, Mark:89  
 ID :2, Name:Ravindar, Class: 3, Mark:98  
 Student details after sorting for descending order  
 ID :2, Name:Ravindar, Class: 3, Mark:98  
 ID :1, Name:Rajesh, Class: 1, Mark:89  
 ID :3, Name:Yoshna, Class: 2, Mark:79  
Note:-

Let's way you want create a logic where you will write comparison logic insted of creating a class by implementing IComparer interface to sort a complex type list. But problem is that a function can not be passed as parameter to sort() method. To help you in this way .Net Framework also introducted the Comparision Delegate. see the blow code example to know how to use the Comparision Delegate.

Comparision Delegate

The following code example illustrates how to use of Comparision Delegate and represend the list with ascending order of class property.

  class Program  
   {  
     static void Main(string[] args)  
     {  
       try  
       {  
         List<Student> students = new List<Student>();  
         students.Add(new Student { ID = 1, Name = "Rajesh", Class = 1, Mark = 89 });  
         students.Add(new Student { ID = 2, Name = "Ravindar", Class = 3, Mark = 98 });  
         students.Add(new Student { ID = 3, Name = "Yoshna", Class = 2, Mark = 79 });  
         Console.WriteLine("Student details before sorting");  
         foreach(Student s in students)  
         {  
           Console.WriteLine("ID :{0}, Name:{1}, Class: {2}, Mark:{3}", s.ID, s.Name, s.Class, s.Mark);   
         }  
         Console.WriteLine();  
         Comparison<Student> classcomparision = new Comparison<Student>(CompareClass);  
         students.Sort(classcomparision);  
         Console.WriteLine("Student details after sorting");  
         foreach (Student s in students)  
         {  
           Console.WriteLine("ID :{0}, Name:{1}, Class: {2}, Mark:{3}", s.ID, s.Name, s.Class, s.Mark);  
         }  
       }  
       catch (Exception ex)  
       {  
         Console.WriteLine(ex.Message);  
       }  
       Console.ReadLine();  
     }  
     public static int CompareClass(Student s1, Student s2)  
     {  
       return s1.Class.CompareTo(s2.Class);  
     }  
     public class Student  
     {  
       public int ID { get; set; }  
       public string Name { get; set; }  
       public int Class { get; set; }  
       public float Mark { get; set; }  
     }  
   }  
Result
 Student details before sorting  
 ID :1, Name:Rajesh, Class: 1, Mark:89  
 ID :2, Name:Ravindar, Class: 3, Mark:98  
 ID :3, Name:Yoshna, Class: 2, Mark:79  
 Student details after sorting  
 ID :1, Name:Rajesh, Class: 1, Mark:89  
 ID :3, Name:Yoshna, Class: 2, Mark:79  
 ID :2, Name:Ravindar, Class: 3, Mark:98  
Note:-

You can use the name of the function in sort method() without using parameter insted of delegate. see the below exampel. Here in this case .Net Framework will use a delegate internally to call your method.

 class Program  
   {  
     static void Main(string[] args)  
     {  
       try  
       {  
         List<Student> students = new List<Student>();  
         students.Add(new Student { ID = 1, Name = "Rajesh", Class = 1, Mark = 89 });  
         students.Add(new Student { ID = 2, Name = "Ravindar", Class = 3, Mark = 98 });  
         students.Add(new Student { ID = 3, Name = "Yoshna", Class = 2, Mark = 79 });  
         Console.WriteLine("Student details before sorting");  
         foreach(Student s in students)  
         {  
           Console.WriteLine("ID :{0}, Name:{1}, Class: {2}, Mark:{3}", s.ID, s.Name, s.Class, s.Mark);   
         }  
         Console.WriteLine();  
         students.Sort(CompareClass);  
         Console.WriteLine("Student details after sorting");  
         foreach (Student s in students)  
         {  
           Console.WriteLine("ID :{0}, Name:{1}, Class: {2}, Mark:{3}", s.ID, s.Name, s.Class, s.Mark);  
         }  
       }  
       catch (Exception ex)  
       {  
         Console.WriteLine(ex.Message);  
       }  
       Console.ReadLine();  
     }  
     public static int CompareClass(Student s1, Student s2)  
     {  
       return s1.Class.CompareTo(s2.Class);  
     }  
     public class Student  
     {  
       public int ID { get; set; }  
       public string Name { get; set; }  
       public int Class { get; set; }  
       public float Mark { get; set; }  
     }  
   }  
Problem:-

The above logics will be fine for the multiple use to avoid writing multiple codes. but what about if the comparison logic is required only one time. In this case ofcourse someone will avoid to write lots of code to implement IComparable or IComparer or use of Comparision Delegate. In this scenario the anonous function can be used where you can write comparison login in one or two lines of code like below code example.

The following code example illustrates how to use of anonymous function and represend the list with ascending order of class property.

 static void Main(string[] args)  
     {  
       try  
       {  
         List<Student> students = new List<Student>();  
         students.Add(new Student { ID = 1, Name = "Rajesh", Class = 1, Mark = 89 });  
         students.Add(new Student { ID = 2, Name = "Ravindar", Class = 3, Mark = 98 });  
         students.Add(new Student { ID = 3, Name = "Yoshna", Class = 2, Mark = 79 });  
         Console.WriteLine("Student details before sorting");  
         foreach(Student s in students)  
         {  
           Console.WriteLine("ID :{0}, Name:{1}, Class: {2}, Mark:{3}", s.ID, s.Name, s.Class, s.Mark);   
         }  
         Console.WriteLine();  
         students.Sort((s1,s2)=>s1.Class.CompareTo(s2.Class));  
         Console.WriteLine("Student details after sorting");  
         foreach (Student s in students)  
         {  
           Console.WriteLine("ID :{0}, Name:{1}, Class: {2}, Mark:{3}", s.ID, s.Name, s.Class, s.Mark);  
         }  
       }  
       catch (Exception ex)  
       {  
         Console.WriteLine(ex.Message);  
       }  
       Console.ReadLine();  
     }  

The sort() function works with the simple type list becuase the simple data type alrady implements IComparable and IComparer interface but the user defined data type or complex data have to use the IComparable or IComparer or Comparision delegate to sort a list.

Summary

In the above discussion, we learned in which scenario the IComparable Interface, IComparer Interface and the Comparision Delegate is usable for sorting a list of complext type. I hope you have enjoyed it and this blog post is helpful to you.

Thanks

Kailash Chandra Behera

An IT Professional with 12 years experience in development life cycle in windows, service and Web based application using Microsoft.Net technologies. Proven record of developing all phases of projects in Microsoft.Net technology from initiation to closure aligning with the company's Business objectives to drive process improvements, competitive advantage and bottom-line gains. -> Good exposure of independently working and developing multiple projects ->Committed to efficient and effective development of projects in a fast-paced and deadline driver environment. Skill :- Develop and design projects in various technologies of Microsoft Technology. Total IT Experience- 13+

1 Comments

Previous Post Next Post

نموذج الاتصال