Home About

January 1st, 2009

Sorting Generic Lists in C# - 2

Sorting a basic generic list in C# is trivial as long as you store basic elements such as strings or integers for which default comparison classes have been defined. In this post we will look into how we can reverse the string sort by implementing your own ICompare comparer, and how you can build your own comparison routines to compare other types. In the example we sort a list (List<>) of people by both their name and their age.

The C# libraries already implement the Quicksort sorting algorithm. So for either a string or an int, sorting the list is as straightforward as calling “Sort”, as show in the below example.

using System;
using System.Collections.Generic;

namespace IComparer
{
    class MainClass
    {
        public static void Main(string[] args)
        {

            List<string> myList = new List<string>();

            myList.Add("z");
            myList.Add("c");
            myList.Add("a");
            myList.Add("d");
            myList.Add("b");

            myList.Sort();

            int cnt = 0;
            foreach(string letter in myList)
                Console.WriteLine("{0} = {1}",cnt++,letter);
        }
    }
}

This code will output:

0 = a
1 = b
2 = c
3 = d
4 = z

But what to do if you would like to reverse the sorting order ? We will have to define our own reverse string comparison routine by sub-classing IComparer. In the essential Compare function we simply call the standard String.Compare function with the parameters in reverse order:

using System;
using System.Collections.Generic;

namespace IComparer
{

    public class ReverseStringComparer : IComparer<string>
    {
        public int Compare(string x, string y)
        {
            // We reverse the result by flipping the input parameters
            return String.Compare(y,x);
        }
    }

    class MainClass
    {
        public static void Main(string[] args)
        {

            List<string> myList = new List<string>();

            myList.Add("z");
            myList.Add("c");
            myList.Add("a");
            myList.Add("d");
            myList.Add("b");

            ReverseStringComparer myComparer = new ReverseStringComparer();        

            myList.Sort(myComparer);

            int cnt = 0;
            foreach(string letter in myList)
                Console.WriteLine("{0} = {1}",cnt++,letter);
        }
    }
}

This code will output:

0 = z
1 = d
2 = c
3 = b
4 = a

Both strings and numbers are very basic types. If you want to sort a list build out of your own datatypes you will need to provide your own ICompare derived comparison class. In the following example we we create struct contained a basic personal record with name, familyname and age. We provide two comparers, one that can sort the list by FamilyName and a second one that sorts the people in the list by their age.

using System;
using System.Collections.Generic;

namespace IComparer
{

    struct Person
    {
        public string FamilyName;
        public string Name;
        public int    Age;
        public Person(string iFamilyName, string iName, int iAge)
        {
            FamilyName = iFamilyName; Name = iName; Age = iAge;
        }
    }

    class PersonComparerByName : IComparer<Person>
    {
        public int Compare(Person x, Person y)
        {
            return String.Compare(x.FamilyName,y.FamilyName);
        }
    }

    class PersonComparerByAge : IComparer<Person>
    {
        public int Compare(Person x, Person y)
        {
            return x.Age - y.Age;
        }
    }

    class MainClass
    {
        public static void Main(string[] args)
        {

            List<Person> myList = new List<Person>();

            myList.Add( new Person("Mulder","Jan",22) );
            myList.Add( new Person("Dijkstra","Hans",45) );
            myList.Add( new Person("Zomer","Nara",25) );
            myList.Add( new Person("Italy","Jaro",38) );
            myList.Add( new Person("Robert","Nico",15) );

            // Sort the people in the list by their last name
            PersonComparerByName myComparerName = new PersonComparerByName();
            myList.Sort(myComparerName);

            int cnt1 = 0;
            foreach(Person aPerson in myList)
                Console.WriteLine("{0} = {1}",cnt1++,aPerson.FamilyName);

            // Sort the people in the list by their age
            PersonComparerByAge myComparerAge = new PersonComparerByAge();
            myList.Sort(myComparerAge);

            int cnt2 = 0;
            foreach(Person aPerson in myList)
                Console.WriteLine("{0} = {1} {2}",cnt2++,aPerson.FamilyName,aPerson.Age);

        }
    }
}

When run, the above code will output:

0 = Dijkstra
1 = Italy
2 = Mulder
3 = Robert
4 = Zomer

0 = Robert 15
1 = Mulder 22
2 = Zomer 25
3 = Italy 38
4 = Dijkstra 45
Share and Enjoy:
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Google
  • Reddit

Tags: , , , , ,

2 Responses to “Sorting Generic Lists in C#”

  1. Jkiley Says:

    Thanks! Finally someone with a simple straightforward example of how to use the IComparer.

  2. Spencer Says:

    Hi there,

    Thanks for these great posts!

    This is a cool way to do the same thing using Extensions:

    string mystring = “string”;
    Console.WriteLine(mystring.Reverse()); //prints “gnirts”

    public static class Extensions
    {
    public static string Reverse(this string x)
    {
    char[] c = x.ToCharArray();
    Array.Reverse(c);
    return new string(c);
    }
    }

Leave a Reply


Recent Comments
  • Ales: Hi, Thanks for the code… I must say I did not experience any errors decrypting any of my messages. I even...
  • JC: Thanks very useful and well explained
  • Thomas: This is a public static class written in the C# language that does not save state. You can call into the...
  • Simon: Thank you very much for this post! It helped me essentially to overcome obstacels to work with mono!
  • Graham: This is a good research for keyboard shortcuts! Some shortcuts are also compatible for Windows OS. I have...