ATTENTION: I've decided to put the upgrade on hold due to a compatibility issue of our server environment with the latest CS installer package. CS 2008 now requires SQL Server 2005 as the backend DB but our database server currenlty has SQL Server 2000 installed on it. I'll resume the upgrade once I figure out when Telligent is releasing a patch to the schema compatibility issue. For now, we will continue to use the old version of CS while waiting for the said patch. If you have any questions about this process, please don't hesitate to post them on our forums and I'll answer them as soon as I can. Thanks for your patience and support guys! I'll let you know as soon as this is resolved. - Keith Rull

Sorting a Generic List of Object in C#

Don't you just love Generics? I mean, it helps you alot in so many ways that everytime you are asked about why you love Generics all you could say is "Uh, type safety?".. Err! We need to change that! There are alot more things to like about Generics than just type safety...  Like code organization... more readable(if you ask me) code... and of course.. type safety(what? i thought you said there's more) :P

Anyway, I use Generics a lot.. when i say alot I mean really really really a lot(is this sentence correct?). I think I've used it in every code i wrote and its really addicting to use(its like anti-perspirant.. something you cant live without :P). I think i've been crazy about Generics since .NET 2.0 beta that i decided to switch jobs because my employer didnt want to migrate to .NET 2.0(uhmmm, this is joke! Just trying to make a point about it which i think i went over the top). One of the things i really love about Generics is the Sort functionality wherein you can right your own custom Comparer to sort the contents of your Generic list.

*update: I over engineered the solution. Thanks to Brian Scott and Andre John Cruz for pointing it out! I have updated this post to reflect the changes(I was doing a compare like this [studen1 is Student] instead of doing student != null in the object validity check inside the comparer and the Print method).

Lets start the demonstration by telling a story about a teacher who just got a list of Students and their grades from the last exam.

First, lets look at the structure of the student information. A student has name and grade.

[Student.cs]

using System;
using System.Collections.Generic;
using System.Text;

namespace KeithRull.LetsSortThat
{
   class Student
   {
      private string _name;
      private double _grade;


      public string Name
      {
         get { return _name; }
         set { _name = value; }
      }

      public double Grade
      {
         get { return _grade; }
         set { _grade = value; }
      }


      public Student(string name, double grade)
      {
         this.Name = name;
         this.Grade = grade;
      }
   }
}

Each student is a part of big list that contains every student that took the exam

[Students.cs]

using System;
using System.Collections.Generic;
using System.Text;

namespace KeithRull.LetsSortThat
{
   class Students: List<Student>
   {
      public void Print()
      {
         Console.WriteLine("Student\t\tGrade");
         Console.WriteLine("-------------------------------");
         foreach (Student student in this)
         {
            if (student != null)
            {
               Console.WriteLine(student.Name + "\t\t" + student.Grade);
            }
         }
      }
   }
}

The next step is for the teacher to add every student on the list of students that took the exam and print the list.

[Program.cs]

using System;
using System.Collections.Generic;
using System.Text;

namespace KeithRull.LetsSortThat
{
   class Program
   {
      static void Main(string[] args)
      {
         Students students = new Students();

         //add the student to the list
         students.Add(new Student("Tom", 83));
         students.Add(new Student("Joe", 86.4));
         students.Add(new Student("Rudy", 85));
         students.Add(new Student("Chris", 87.2));
         students.Add(new Student("Keith", 85.5));
         students.Add(new Student("Pepe", 75.1));
         students.Add(new Student("Juan", 88.8));
         students.Add(new Student("Pedro", 75.1));
         students.Add(new Student("Pablo", 75.1));
         students.Add(new Student("Jose", 79.3));
         students.Add(new Student("Tommy", 88.9));

         //print the list
         students.Print();
         Console.ReadLine();
      }
   }
}

[Execution Results]

Student         Grade
---------------------
Tom             83
Joe             86.4
Rudy            85
Chris           87.2
Keith           85.5
Pepe            75.1
Juan            88.8
Pedro           75.1
Pablo           75.1
Jose            79.3
Tommy           88.9

After printing the list... The teacher realized that the list is not ordered by grade.. He then decided that the report would look better if the grades are ordered in descending order so that he can easily spot the student who didn't do well in the exam instead of browsing each line.

[StudentGradeComparer.cs]

using System;
using System.Collections.Generic;
using System.Text;

namespace KeithRull.LetsSortThat
{
   class StudentGradeComparer: IComparer<Student>
   {

      #region IComparer<Student> Members

      public int Compare(Student student1, Student student2)
      {
         int returnValue = 1;
         if (student1 != null && student2 != null)
         {
            returnValue = student2.Grade.CompareTo(student1.Grade);
         }

         return returnValue;
      }

      #endregion
   }
}

[revised Program.cs]

using System;
using System.Collections.Generic;
using System.Text;

namespace KeithRull.LetsSortThat
{
   class Program
   {
      static void Main(string[] args)
      {
         Students students = new Students();

         //add the student to the list
         students.Add(new Student("Tom", 83));
         students.Add(new Student("Joe", 86.4));
         students.Add(new Student("Rudy", 85));
         students.Add(new Student("Chris", 87.2));
         students.Add(new Student("Keith", 85.5));
         students.Add(new Student("Pepe", 75.1));
         students.Add(new Student("Juan", 88.8));
         students.Add(new Student("Pedro", 75.1));
         students.Add(new Student("Pablo", 75.1));
         students.Add(new Student("Jose", 79.3));
         students.Add(new Student("Tommy", 88.9));

         //implement our custom comparer for grades
         students.Sort(new StudentGradeComparer());
         students.Print();
         Console.ReadLine();
      }
   }
}

[Execution Result]

Student         Grade
-----------------------
Tommy           88.9
Juan            88.8
Chris           87.2
Joe             86.4
Keith           85.5
Rudy            85
Tom             83
Jose            79.3
Pablo           75.1
Pepe            75.1
Pedro           75.1

Looking at the result.. He was really happy.. but.. he realized that the names are not alphabetized.. Pedro should come before Pepe because he thinks that names should be in ascending order and rades should be in descending order... being a picky as he is, he decided to add another sort criteria..

[StudentGradeAndNameComparer]

using System;
using System.Collections.Generic;
using System.Text;

namespace KeithRull.LetsSortThat
{
   class StudentGradeAndNameComparer : IComparer<Student>
   {
      #region IComparer<Student> Members

      public int Compare(Student student1, Student student2)
      {
         int returnValue = 1;
         if (student1 != null && student2 == null)
         {
            returnValue = 0;
         }
         else if (student1 == null && student2 != null)
         {
            returnValue = 0;
         }
         else if (student1 != null && student2 != null)
         {
            if (student1.Grade.Equals(student2.Grade))
            {
               returnValue = student1.Name.CompareTo(student2.Name);
            }
            else
            {
               returnValue = student2.Grade.CompareTo(student1.Grade);
            }
         }
         return returnValue;
      }
   
      #endregion
   }
}

[Modified Program.cs v2]

using System;
using System.Collections.Generic;
using System.Text;

namespace KeithRull.LetsSortThat
{
   class Program
   {
      static void Main(string[] args)
      {
         Students students = new Students();

         //add the student to the list
         students.Add(new Student("Tom", 83));
         students.Add(new Student("Joe", 86.4));
         students.Add(new Student("Rudy", 85));
         students.Add(new Student("Chris", 87.2));
         students.Add(new Student("Keith", 85.5));
         students.Add(new Student("Pepe", 75.1));
         students.Add(new Student("Juan", 88.8));
         students.Add(new Student("Pedro", 75.1));
         students.Add(new Student("Pablo", 75.1));
         students.Add(new Student("Jose", 79.3));
         students.Add(new Student("Tommy", 88.9));

         //implement our custom comparer for grades and names
         students.Sort(new StudentGradeAndNameComparer());
         students.Print();
         Console.ReadLine();
      }
   }
}

[Execution Result]

Student         Grade
---------------------
Tommy           88.9
Juan            88.8
Chris           87.2
Joe             86.4
Keith           85.5
Rudy            85
Tom             83
Jose            79.3
Pablo            75.1
Pedro           75.1
Pepe           75.1

And finally... He is happy! Sweet.

Hope you learned something about Generics, IComparer, Comparing objects and how crazy teachers can be :)

Download the code here: KeithRull.LetsSortThat.zip (23.85 KB)


Posted Feb 23 2007, 03:39 PM by keithrull
Filed under: , , ,

Comments

Brian Scott wrote re: Sorting a Generic List of Object in C#
on 02-23-2007 7:41 PM

NIce explanation, however I am just wondering about these lines:

if (student1 is Student && student2 is Student)

...

foreach (Student student in this)

{

   if (student is Student)

...

Aren't you performing some redundant casts there? The classes are already strongly typed so the cast and check seems unnecessary.

keithrull wrote re: Sorting a Generic List of Object in C#
on 02-23-2007 7:54 PM

Thanks Brian!

i found out that you can still add a null to the list, something like:

students.Add(null);

The code above would break the comparer and that is the reason why i added those validation on the compare method.

cruizer wrote re: Sorting a Generic List of Object in C#
on 02-23-2007 8:32 PM

then why not check for null instead, keith?

keithrull wrote re: Sorting a Generic List of Object in C#
on 02-23-2007 10:29 PM

ahh, that's true! my bad.. it's called "Over Engineering". I'll update the post. Thanks!

lamia wrote re: Sorting a Generic List of Object in C#
on 02-24-2007 10:51 PM

Nice post Keith! Very very very interesting indeed. However, I'm really against the use of the word "and" on method names like StudentGradeAndNameComparer(). It seems that the method is doing other things than what it is intended to do. Overall thoough, I really admire your obsession with generics! Medyo tinamaan ako dun sa  "Uh, type safety?" na part bwahahaha!

cruizer wrote re: Sorting a Generic List of Object in C#
on 02-25-2007 1:44 PM

@lamia, what other things is it doing? It only implements one method, and that is from the IComparer method. I guess its purpose is very clear here. Together with StudentGradeComparer, they both form a strategy pattern when it comes to sorting the list of students.

to me generics is useful not simply for type safety but because it's an easy way to construct typed lists. i wouldn't wanna go back to the old days of .NET 1.1 Stick out tongue and it's also easy to use generics for reusing short helper methods across different data types. like in one web app I did months back, I used generics in delegates to reuse a code snippet that instantiates and initializes an object if it cannot be found in the Application, Session or Cache store of the ASP.NET web app.

lamia wrote re: Sorting a Generic List of Object in C#
on 02-25-2007 6:58 PM

@cruizer

Sorry, I think I mistook the constructor for a mathod name(ok, that is also a method). My reason for avoiding the use of "And" for whatever purpose they may serve is like what I said, it could look that the method(or whatever) could be doing things other than what they are intended to do. I could be wrong though, but things that violate the SRP would usually start from methods that have the word "And" with them.

As for me, in Java. The only benefit I've had so far aside from code security is the elimination of casting. Saves me a lot of typing. And besides, the java collections framework is flooded with them so it was necessary to understand what they're good for. Hope to see more examples from Keith! :)

cruizer wrote re: Sorting a Generic List of Object in C#
on 02-25-2007 7:49 PM

i understand. it really depends on what the class/method is doing. as for the name...i'm sure keith just put it in because it was -- to him -- more readable (StudentGradeAndNameComparer, in constrast to StudentGradeNameComparer)

keithrull wrote re: Sorting a Generic List of Object in C#
on 02-26-2007 10:41 AM

@cruizer: you read my mind! :)

@lamia: Generics are fun :) Somebody IMed me today saying that i should have my demo something like a CutenessComparer instead of StudentGrades because he thinks if would be funnier :)

lamia wrote re: Sorting a Generic List of Object in C#
on 02-26-2007 11:14 PM

Hmmm... And maybe your implementation would put me in the zero index?

Keith Rull wrote Sorting a Generic List of Object in C# using IComparable and Anonymous Delegates
on 03-23-2007 2:23 PM

A few weeks ago I wrote an article on how to use IComparer and how it was easy it is to create a custom

ashley wrote re: Sorting a Generic List of Object in C#
on 09-24-2007 7:10 AM

very useful for me - thank you!!

Spirro wrote re: Sorting a Generic List of Object in C#
on 03-28-2008 5:04 PM

THX!!!

Great exampel! Now I'm finnaly finnished with my first step in to the C# world :)

Ride On!!

//Spirro

Magnot wrote re: Sorting a Generic List of Object in C#
on 10-22-2008 2:02 AM

Thank you for this sample. It was userful for me as well.

Alex wrote re: Sorting a Generic List of Object in C#
on 10-23-2008 10:05 AM

This was very helpful. Thank you very much.

... wrote re: Sorting a Generic List of Object in C#
on 10-25-2008 10:12 AM

Nice site you have

Add a Comment

(required)  
(optional)
(required)  
Remember Me?

Enter the numbers above:

Copyright DevPinoy 2005-2008