Working with lists is something developers do almost everyday. One of the most common tasks when we think about lists is sorting them. Fortunately, sorting lists in C# is not very complicated when it comes to primitive types and strings, but are slightly more complicated when we create lists of our own objects. In this tutorial we’ll go through some of the common ways to sort lists in C#.
Update: I have also created a video on this topic so if you think that it’s easier to follow the video, here it is:
Let’s start with a short and simple example. Let’s assume that we create a list of names and we add some names to the list:
[code language=”csharp”]
List<string> names = new List<string>();
names.Add(“John”);
names.Add(“Dan”);
names.Add(“Zack”);
names.Add(“Cristina”);
[/code]
What we have is a list of strings containing names that were randomly added to the list. Fortunately, List<T> has an own sort method that we can use to sort the names and then write each name to the console.
[code language=”csharp”]
names.Sort();
Console.WriteLine(“\nSorted list:\n”);
foreach (string name in names)
{
Console.WriteLine(name);
}
[/code]
If you put this code in your own console application an run it, you’ll noticed that the output is now sorted alphabetically. This might be convenient a lot of times, but unfortunately it won’t be very helpful if you want to sort the list by the length of each name. There are, however, several options that we could use to sort a list the way we want. Since I’ve already mentioned to Sort() method, I will stick to it for now.
Off topic: In Visual Studio it’s easy to check how different types are implemented by selecting the type name and pressing F12. This will go to the type definition and it always gives you a lot of insights on how different types and classes are supposed to work, what methods are available, which interfaces are implemented and so on.
If we go to the List<T> definition we’ll notice that Sort() has three other overloads. This means that we can call the method in fourdifferent ways.
[code language=”csharp” highlight=”1,4″]
public void Sort(Comparison<T> comparison);
public void Sort(int index, int count, IComparer<T> comparer);
public void Sort();
public void Sort(IComparer<T> comparer);
[/code]
I will concentrate only on the highlighted method overloads since this tutorial is intended for beginners. Just as a summary, the method overload on the second line would perform a sort starting from a specified index, for a specified length and using an own comparer ( if it’s null, it will use the default comparer).
Sort(Comparison<T> comparison)
This overload takes a Comparison<T> delegate that will compare two objects of the same time. Don’t bother for now about “delegates” since I’ll write a dedicated article about the topic. For now just think of a delegate as a parameter that you can pass in the Sort() method. Coming back to our list of names and the desire to sort the list based on the length of each name, we could simply provide a lambda expression (will also be covered in a dedicated article. For now think of it as normal code that you can write inside a method) that will instruct the Sort() method how exactly to perform sorting.
[code language=”csharp”]
names.Sort((x, y) => x.Length.CompareTo(y.Length));
Console.WriteLine(“\nSorting according to string length:\n”);
foreach (string name in names)
{
Console.WriteLine(name);
}
/*Output:
Sorting according to string length:
Dan
John
Zack
Cristina
*/
[/code]
That’s cool! The variable names “x” and “y” are not important. You can use whatever other names you want. Since sorting is done on a list of string, the provided variables will be always considered as strings and that’s why the “Length” property is available to use on them. That’s how lambda expressions work. In this case, the lambda expression that we provided is considered to be a Comparison<T> delegate and that’s how this magic works.
Sort(IComparer<T> comparer)
This overload takes a custom comparer to perform the sorting. This means that we would need to create our own class that implements IComparer<T>. For beginners this is probably a little bit harder to grasp, but it will solve a lot of problems when you have to define more complex comparison rules and will make your code look more beautiful. Let’s don’t get disheartened by the added complexity and try to implement this method. Our aim is to achieve the same type of sorting based on string length as previously, but by using our own comparer class. So let’s define the class.
[code language=”csharp”]
using System;
using System.Collections.Generic;
using System.Text;
namespace Sorting
{
public class NameComparer : IComparer<string>
{
public int Compare(string x, string y)
{
if (x == null)
{
if (y == null)
{
// If x is null and y is null, they’re
// equal.
return 0;
}
else
{
// If x is null and y is not null, y
// is greater.
return -1;
}
}
else
{
// If x is not null…
//
if (y == null)
// …and y is null, x is greater.
{
return 1;
}
else
{
// …and y is not null, compare the
// lengths of the two strings.
//
int retval = x.Length.CompareTo(y.Length);
if (retval != 0)
{
// If the strings are not of equal length,
// the longer string is greater.
//
return retval;
}
else
{
// If the strings are of equal length,
// sort them with ordinary string comparison.
//
return x.CompareTo(y);
}
}
}
}
}
}
[/code]
And then we create an instance of the NameComparer class and pass it as custom comparer to the Sort() method.
[code language=”csharp”]
NameComparer nc = new NameComparer();
names.Sort(nc);
Console.WriteLine(“\nSorting according to string length with custom comparer:\n”);
foreach (string name in names)
{
Console.WriteLine(name);
}
/*Output: Sorting according to string length with custom comparer:
Dan
John
Zack
Cristina */
[/code]
As you can see, the result is exactly the same. The major difference is, however, that we have used our custom comparer to perform sorting which would allow us to implement even more complex logic in our comparison. This will be extremely useful when you’ll want to sort a list of your own objects and will probably need specify also the criteria used for sorting. Initially I wanted to cover here also this topic, but the article got fairly long, so I’ll write about sorting list of objects in a separate article.
How useful was this post?
Click on a star to rate it!
Average rating / 5. Vote count:
Dan Patrascu-Baba
Latest posts by Dan Patrascu-Baba (see all)
- Configuration and environments in ASP.NET Core - 25/11/2019
- GraphQL in the .NET ecosystem - 19/11/2019
- A common use case of delegating handlers in ASP.NET API - 12/11/2019
The article was otherwise good but all the example code was badly formatted (no indentation) and thus was hard to read.