Sorting a .Net list with lambdas
I love linq. I would wager that most developers who have done much with it share a similar love.
It makes our lives easier. It eliminates writing copies amounts of loops, parsing xml, interacting with databases, you name it. It’s great.
When I run into a situation where linq does not have an obvious tie in, I start to get a little anxious, (pathetic I realize).
Today I was faced with a situation where I had a list of custom classes that I needed to sort.
This being a list, OrderBy was nowhere to be found.
So, I returned to my roots and started writing a compare for my class so that I could use the Sort command that *is *part of the List generic type. That is when it struck me that I could probably accomplish this using a lambda. It turns out that I was correct. Lambda’s were a perfect fit for this scenario. The code remained clean and concise and I was saved having to write additional methods just to accomplish a one-off scenario on what was a otherwise complete project.
Lamdas are a progression in C# past anonymous methods. In the code below, I show how the code would be implemented with separate function, an anonymous method and finally, with a Lambda expression.
First, the test class that we’ll be working with:
public class MyClass {
public int propA { get; set; }
public int propB { get; set; }
public int propC { get; set; }
}
Our test class:
public class Tester {
public void Main() {
List list = new List();
list.Add(new MyClass() { propA = 1, propB = 2, propC = 3 });
list.Add(new MyClass() { propA = 2, propB = 3, propC = 4 });
list.Add(new MyClass() { propA = 3, propB = 4, propC = 5 });
list.Add(new MyClass() { propA = 4, propB = 5, propC = 6 });
}
}
Now then, we write a custom comparer. Not a lot of code, but you can imagine how this extrapolates over various properties for large classes.
public class Tester {
private static int CompareByPropA(MyClass a, MyClass b) {
return a.propA.CompareTo(b.propA);
}
public void Main() {
List list = new List();
list.Add(new MyClass() { propA = 1, propB = 2, propC = 3 });
list.Add(new MyClass() { propA = 2, propB = 3, propC = 4 });
list.Add(new MyClass() { propA = 3, propB = 4, propC = 5 });
list.Add(new MyClass() { propA = 4, propB = 5, propC = 6 });
//Using the comparer built into the MyClass method
list.Sort(CompareByPropA);
}
}
This time, we drop the custom comparer and implement the sort using an anonymous method.
public class Tester {
public void Main() {
List list = new List();
list.Add(new MyClass() { propA = 1, propB = 2, propC = 3 });
list.Add(new MyClass() { propA = 2, propB = 3, propC = 4 });
list.Add(new MyClass() { propA = 3, propB = 4, propC = 5 });
list.Add(new MyClass() { propA = 4, propB = 5, propC = 6 });
//Using an anonymous method
list.Sort(delegate(MyClass a, MyClass b) {
return a.propA.CompareTo(b.propA); });
}
}
Finally, we rewrite the anonymous method into a Lambda. It is still easy to read and much more concise.
public class Tester {
public void Main() {
List list = new List();
list.Add(new MyClass() { propA = 1, propB = 2, propC = 3 });
list.Add(new MyClass() { propA = 2, propB = 3, propC = 4 });
list.Add(new MyClass() { propA = 3, propB = 4, propC = 5 });
list.Add(new MyClass() { propA = 4, propB = 5, propC = 6 });
//Using a Lambda
list.Sort((a, b) => a.propA.CompareTo(b.propA));
}
}
So, next time you go to write custom compare code, step back and see if you can do it a little more simply. If you are going to be using your comparison code in more than one place, then perhaps it is still a better idea to implement it using that route vs the lambda. If it is a one-off thing, then a lambda and some linq can be a beautiful thing!