Lambda Expressions
IComparer
C# Programming
Software Development
Coding Practices

Using lambda expression in place of IComparer argument

Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms

Introduction

In C#, methods like Array.Sort() and List.Sort() accept an IComparer<T> argument for custom sorting. Instead of creating a separate class that implements IComparer<T>, you can pass a lambda expression using Comparer<T>.Create(). This converts a two-parameter lambda into a valid IComparer<T> instance, making sort customization a one-liner instead of a multi-class affair.

The Traditional IComparer Approach

Without lambdas, custom sorting requires a dedicated class:

csharp
1class NameLengthComparer : IComparer<string>
2{
3    public int Compare(string x, string y)
4    {
5        return x.Length.CompareTo(y.Length);
6    }
7}
8
9// Usage
10string[] names = { "Charlie", "Alice", "Bob", "Diana" };
11Array.Sort(names, new NameLengthComparer());
12// Result: ["Bob", "Alice", "Diana", "Charlie"]

This works but creates boilerplate for every custom sort order.

Using Comparer<T>.Create with Lambda

Comparer<T>.Create() takes a Comparison<T> delegate (a lambda with two parameters) and wraps it in an IComparer<T>:

csharp
1string[] names = { "Charlie", "Alice", "Bob", "Diana" };
2
3// Sort by string length using a lambda
4Array.Sort(names, Comparer<string>.Create((x, y) => x.Length.CompareTo(y.Length)));
5// Result: ["Bob", "Alice", "Diana", "Charlie"]
6
7// Sort by last character
8Array.Sort(names, Comparer<string>.Create((x, y) => x[^1].CompareTo(y[^1])));

Direct Comparison<T> Delegate

Some overloads accept a Comparison<T> delegate directly, so you can skip Comparer<T>.Create:

csharp
1List<string> names = new() { "Charlie", "Alice", "Bob", "Diana" };
2
3// List.Sort accepts Comparison<T> directly
4names.Sort((x, y) => x.Length.CompareTo(y.Length));
5
6// Array.Sort also accepts Comparison<T>
7string[] arr = { "Charlie", "Alice", "Bob", "Diana" };
8Array.Sort(arr, (x, y) => x.Length.CompareTo(y.Length));

The difference: Sort(Comparison<T>) takes a delegate directly, while methods requiring IComparer<T> need Comparer<T>.Create().

Practical Examples

Sort Objects by Multiple Fields

csharp
1var people = new List<(string Name, int Age)>
2{
3    ("Alice", 30), ("Bob", 25), ("Charlie", 30), ("Diana", 25)
4};
5
6// Sort by age, then by name
7people.Sort((a, b) =>
8{
9    int ageCompare = a.Age.CompareTo(b.Age);
10    return ageCompare != 0 ? ageCompare : string.Compare(a.Name, b.Name);
11});
12// (Bob, 25), (Diana, 25), (Alice, 30), (Charlie, 30)

Descending Sort

csharp
1int[] numbers = { 3, 1, 4, 1, 5, 9 };
2
3// Ascending (default)
4Array.Sort(numbers, (x, y) => x.CompareTo(y));
5// 1, 1, 3, 4, 5, 9
6
7// Descending — swap x and y
8Array.Sort(numbers, (x, y) => y.CompareTo(x));
9// 9, 5, 4, 3, 1, 1

Case-Insensitive String Sort

csharp
1string[] words = { "banana", "Apple", "cherry", "Blueberry" };
2
3Array.Sort(words, (x, y) => string.Compare(x, y, StringComparison.OrdinalIgnoreCase));
4// Apple, banana, Blueberry, cherry

SortedSet and SortedDictionary

Collections that require IComparer<T> in their constructor need Comparer<T>.Create:

csharp
1// SortedSet with custom comparer
2var set = new SortedSet<string>(
3    Comparer<string>.Create((x, y) => x.Length.CompareTo(y.Length))
4);
5set.Add("Charlie");
6set.Add("Alice");
7set.Add("Bob");
8// Iteration order: Bob, Alice, Charlie (by length)
9
10// SortedDictionary with reverse key order
11var dict = new SortedDictionary<int, string>(
12    Comparer<int>.Create((x, y) => y.CompareTo(x))
13);
14dict[1] = "one";
15dict[3] = "three";
16dict[2] = "two";
17// Keys iterate: 3, 2, 1

LINQ OrderBy (No IComparer Needed)

LINQ's OrderBy and ThenBy use key selectors, which are even simpler than comparison lambdas:

csharp
1var sorted = names.OrderBy(n => n.Length).ThenBy(n => n);
2
3// But if you need a custom IComparer with LINQ:
4var sorted = names.OrderBy(n => n, Comparer<string>.Create(
5    (x, y) => x.Length.CompareTo(y.Length)
6));

When to Use Which

ScenarioApproach
List.Sort() or Array.Sort()Lambda directly: (x, y) => ...
Constructor requiring IComparer<T>Comparer<T>.Create((x, y) => ...)
Complex reusable comparison logicSeparate IComparer<T> class
LINQ sortingOrderBy(x => x.Property)

Common Pitfalls

  • Inconsistent comparison: A comparer must be consistent — if Compare(a, b) < 0, then Compare(b, a) > 0. An inconsistent lambda causes ArgumentException or unpredictable sort order.
  • Forgetting null handling: If the collection can contain nulls, the lambda must handle null arguments. x.CompareTo(y) throws NullReferenceException if x is null.
  • Using Comparer<T>.Create when Comparison<T> is accepted: List.Sort() and Array.Sort() accept Comparison<T> directly — no need for Comparer<T>.Create. Use Create only when the API specifically requires IComparer<T>.
  • Subtraction instead of CompareTo for integers: (x, y) => x - y works for small values but overflows for extreme int values (e.g., int.MinValue - 1). Always use x.CompareTo(y).
  • Mutating state in the comparer lambda: The comparison function should be pure — no side effects. Sorting algorithms call the comparer unpredictably many times, and side effects lead to bugs.

Summary

  • Use Comparer<T>.Create((x, y) => ...) to create an IComparer<T> from a lambda expression
  • List.Sort() and Array.Sort() accept Comparison<T> lambdas directly without Create
  • For SortedSet, SortedDictionary, and other constructors requiring IComparer<T>, use Comparer<T>.Create
  • Always use .CompareTo() instead of subtraction to avoid integer overflow
  • LINQ's OrderBy(x => x.Property) is simpler than comparison lambdas when you just need to sort by a key

Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms