Home About

January 1st, 2009

Sorting Generic Lists in C# - 0

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: , , , , ,

Leave a Reply


Recent Comments
  • Hakbor: This works fine. But to get the NUnit to use my current tests (and not the old ones) , it is not sufficient...
  • Alberto: Your plugin is very useful; I installed it on several different blogs I manage and I’m very happy with...
  • Nelson: Saved me from doing it myself. Good article.
  • andy: i am currently playing taiwanese server wow in 奈辛瓦里(PVP) and i would like to realm transfer to...
  • berties: any english speaking playing on a taiwanese server?