CodeGym /Courses /C# SELF /Sorting Collections

Sorting Collections

C# SELF
Level 29 , Lesson 2
Available

1. Introduction

If you've ever had a sock drawer where you tried to find a matching pair, you've already faced the sorting problem. When everything's a mess, finding what you need turns into a quest. It's the same story with collections in programming.

Sorting is the process of arranging elements in a collection by some criteria (like alphabetically, by value, date, etc.). This matters for:

  • Showing data to users (nobody likes chaos).
  • Making search easier (for example, binary search only works on sorted collections).
  • Comparisons, reports, exports, and other stuff.

Million dollar question: "But what if I only have five elements, do I really need to sort?" — Theoretically, sure, but as soon as five turns into five hundred or five thousand, you can't live without automation.

In .NET, there are two main ways to sort:

  • Changing the original collection (like sorting a List<T> with the Sort method).
  • Creating a new sorted copy of the collection (like cloning an array and then sorting it).

Sorting lists with the .Sort() method

The Sort() method is available on the List<T> class, since this class implements the IList<T> interface, giving you index access and the ability to change the order of elements.

Example — sorting numbers in ascending order:


using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var numbers = new List<int> { 5, 2, 9, 1, 5, 6 };
        numbers.Sort();
        Console.WriteLine("Sorting in ascending order:");
        foreach(var number in numbers)
        {
            Console.Write($"{number} "); // 1 2 5 5 6 9
        }
    }
}

Here, sorting happens "in place": the original numbers list is changed, its elements are rearranged.

Sorting strings

Sorting works great for strings too:


var words = new List<string> { "orange", "apple", "banana", "pear" };
words.Sort();
Console.WriteLine(string.Join(", ", words)); // orange, banana, pear, apple

Fun fact: by default, string sorting goes by Unicode order, not "human" alphabetical order (especially for different languages, keep this in mind for multilingual apps).

2. Sorting by custom rules

Sometimes the default sorting just doesn't cut it. Say, you want to sort users not by name, but by age or registration date.

Sorting with a lambda expression (the Sort(Comparison<T>) method)

You can call the Sort method and pass in a special sorting rule — a function that compares two elements.

Sorting users by age:


class User
{
    public string Name { get; set; }
    public int Age { get; set; }
}

// ...

var users = new List<User>
{
    new User { Name = "Alice", Age = 30 },
    new User { Name = "Bob", Age = 25 },
    new User { Name = "Eve", Age = 35 }
};

users.Sort((u1, u2) => u1.Age.CompareTo(u2.Age));

foreach (var user in users)
{
    Console.WriteLine($"{user.Name}: {user.Age}");
}
// Output:
// Bob: 25
// Alice: 30
// Eve: 35

How does this magic work? The lambda (u1, u2) => u1.Age.CompareTo(u2.Age) returns a negative number if u1 is younger, positive if older, and 0 if their ages match.

Using the IComparer<T> interface

Sometimes you want to move the sorting rule into a separate class, like if you have a bunch of collections and complex logic.


class UserAgeComparer : IComparer<User>
{
    public int Compare(User x, User y)
    {
        return x.Age.CompareTo(y.Age);
    }
}

// ...

var users = new List<User>{ /* ... */ };
users.Sort(new UserAgeComparer()); // now sorting by age

This is handy if you need the same sorting in different parts of your program or have lots of different sorts.

Sorting by multiple fields manually

If some users have the same age, but you want to sort them by name within the same age group:


users.Sort((u1, u2) => {
    int ageCompare = u1.Age.CompareTo(u2.Age);
    if (ageCompare != 0)
        return ageCompare;
    else
        return u1.Name.CompareTo(u2.Name);
});

Now sorting goes by age first, then by name.

3. Sorting a copy of a collection (without changing the original)

If you don't want to mess with the original list, copy it before sorting:


var copy = new List<int>(numbers);
copy.Sort();

For custom objects — same deal:


var usersCopy = new List<User>(users);
usersCopy.Sort((a, b) => a.Age.CompareTo(b.Age));

4. Sorting arrays

With arrays (T[]) it's also pretty straightforward:


int[] numbers = { 4, 2, 9, 7 };
Array.Sort(numbers); // original array is changed

For "custom" sorting:


Array.Sort(numbers, (a, b) => b.CompareTo(a)); // sorting in descending order

Heads up, Array.Sort changes the original array, doesn't return a new one. If you want to keep the original, copy the array first:


int[] oldNumbers = { 3, 2, 1 };
int[] copy = (int[])oldNumbers.Clone();
Array.Sort(copy);

5. "Sorting" dictionaries (Dictionary<TKey, TValue>)

Dictionary<TKey, TValue> is, by nature, an unordered collection (meaning it doesn't guarantee order when you enumerate it). But sometimes you want to get "sorted pairs."

To get sorted keys or values, make a list, copy the pairs there, and sort however you want:


var dict = new Dictionary<string, int>
{
    { "apple", 2 },
    { "orange", 5 },
    { "pear", 3 }
};

// Sorting by key:
var keyValueList = new List<KeyValuePair<string, int>>(dict);
keyValueList.Sort((a, b) => a.Key.CompareTo(b.Key));
foreach (var kv in keyValueList)
{
    Console.WriteLine($"{kv.Key}: {kv.Value}");
}

// Sorting by value:
keyValueList.Sort((a, b) => a.Value.CompareTo(b.Value));
foreach (var kv in keyValueList)
{
    Console.WriteLine($"{kv.Key}: {kv.Value}");
}

If you want to get a sorted list of keys or values:


var sortedKeys = new List<string>(dict.Keys);
sortedKeys.Sort();

var sortedValues = new List<int>(dict.Values);
sortedValues.Sort();

But remember, the Dictionary structure itself doesn't change — you're just getting a sorted enumeration. In .NET 9, there will be an OrderedDictionary<TKey, TValue> that keeps the order of elements. Not often needed, but sometimes you want that.

6. Handy details

Do you have to implement a comparison interface?

It's simple: if you want your objects to "know" how to compare themselves (like by date or name), implement the IComparable<T> interface.


class Product : IComparable<Product>
{
    public string Name { get; set; }
    public decimal Price { get; set; }

    public int CompareTo(Product other)
    {
        return Price.CompareTo(other.Price);
    }
}

Now you can do:


var products = new List<Product> { /* ... */ };
products.Sort(); // sorts by price

If the default comparison isn't what you want — use IComparer<T> or pass a lambda, like above.

Sorting a user list alphabetically

Say, your app has a user list:


List<string> users = new List<string> { "Victor", "Anna", "Ekaterina", "Boris" };
users.Sort(); // now users is sorted: Anna, Boris, Victor, Ekaterina

Sorting tasks by urgency


class Task
{
    public string Title { get; set; }
    public int Priority { get; set; } // 1 - urgent, 2 - important, 3 - can wait
}

var todo = new List<Task>
{
    new Task { Title = "Do homework", Priority = 2 },
    new Task { Title = "Buy bread", Priority = 1 },
    new Task { Title = "Watch a show", Priority = 3 }
};

todo.Sort((a, b) => a.Priority.CompareTo(b.Priority));

foreach (var task in todo)
    Console.WriteLine($"{task.Priority}: {task.Title}");

Comparing sorting methods

Collection Changes in place? Sorting method Can you set a rule?
List<T>
Yes
Sort()
Yes: lambda or IComparer
T[]
Yes
Array.Sort()
Yes: lambda or IComparer
Dictionary<TKey, TValue>
No — (make a list and sort it) Yes: via lambda or IComparer

7. Typical mistakes and sorting gotchas

Sorting in place — changes the original collection! If your original data shouldn't change — copy it first.

Trying to sort an immutable collection (like ReadOnlyCollection<T>) will throw a runtime error.

String comparison is different in different cultures: sorting strings (especially with Cyrillic, umlauts, etc.) can be different on various locales. For correct sorting, use Comparer.Create(...) with the right culture.

Sorting dictionaries doesn't change their structure — you always get a new sequence of pairs (or a new list).

For complex order, use the IComparer<T> interface with your logic.

Here's an example of sorting gone wrong (classic rookie mistake):


var numbers = new List<int> { 1, 2, 3 };
var sorted = numbers.Sort(); // ERROR: Sort() returns void!

The right way:


numbers.Sort(); // changes numbers in place

// If you want a new collection:
var sorted = new List<int>(numbers);
sorted.Sort();
2
Task
C# SELF, level 29, lesson 2
Locked
Sorting a list of strings in alphabetical order
Sorting a list of strings in alphabetical order
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION