C# tutorials > Core C# Fundamentals > Data Structures and Collections > How do you sort a Collection in C# (`List<T>.Sort()`, LINQ `OrderBy`)?

How do you sort a Collection in C# (`List<T>.Sort()`, LINQ `OrderBy`)?

Sorting collections is a fundamental operation in C#. This tutorial explores two primary methods: the List<T>.Sort() method and the LINQ OrderBy (and OrderByDescending) methods. We will cover how to use each method, their differences, performance considerations, and when to use each effectively.

Sorting with `List.Sort()`

The List<T>.Sort() method sorts the elements of the entire List<T> in place. This means it modifies the original list directly. By default, it sorts in ascending order using the default comparer for the type T. In the example above, it sorts a list of integers and a list of strings alphabetically.

Key characteristics:

  • Sorts in place.
  • Modifies the original list.
  • Uses the default comparer for the type or a custom comparer if provided.

using System;
using System.Collections.Generic;

public class Example
{
    public static void Main(string[] args)
    {
        List<int> numbers = new List<int> { 5, 2, 8, 1, 9 };

        Console.WriteLine("Original List: " + string.Join(", ", numbers));

        numbers.Sort(); // Sorts the list in place (ascending order)

        Console.WriteLine("Sorted List (List.Sort()): " + string.Join(", ", numbers));

        List<string> names = new List<string> { "Charlie", "Alice", "Bob" };
        names.Sort();
        Console.WriteLine("Sorted Names (List.Sort()): " + string.Join(", ", names));
    }
}

Sorting with LINQ `OrderBy`

LINQ's OrderBy method provides a more flexible way to sort collections. It returns a new sorted IEnumerable<T> without modifying the original collection. You can also use OrderByDescending to sort in descending order.

Key characteristics:

  • Does not modify the original list.
  • Returns a new sorted IEnumerable<T>.
  • Allows for complex sorting criteria using lambda expressions.
  • Can be chained with other LINQ methods.

using System;
using System.Collections.Generic;
using System.Linq;

public class Example
{
    public static void Main(string[] args)
    {
        List<int> numbers = new List<int> { 5, 2, 8, 1, 9 };

        Console.WriteLine("Original List: " + string.Join(", ", numbers));

        IEnumerable<int> sortedNumbers = numbers.OrderBy(x => x); // Sorts using LINQ

        Console.WriteLine("Sorted List (LINQ OrderBy): " + string.Join(", ", sortedNumbers));

        List<string> names = new List<string> { "Charlie", "Alice", "Bob" };
        IEnumerable<string> sortedNames = names.OrderBy(name => name);
        Console.WriteLine("Sorted Names (LINQ OrderBy): " + string.Join(", ", sortedNames));

        IEnumerable<int> descendingNumbers = numbers.OrderByDescending(x => x);
        Console.WriteLine("Sorted List (LINQ OrderByDescending): " + string.Join(", ", descendingNumbers));


    }
}

Sorting with Custom Comparer

Both List<T>.Sort() and LINQ OrderBy allow you to specify a custom comparer to define how elements should be compared. For List<T>.Sort(), you can implement the IComparer<T> interface. With LINQ, you typically use a lambda expression to define the sorting criteria inline.

using System;
using System.Collections.Generic;

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

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

public class Example
{
    public static void Main(string[] args)
    {
        List<Person> people = new List<Person>
        {
            new Person { Name = "Charlie", Age = 30 },
            new Person { Name = "Alice", Age = 25 },
            new Person { Name = "Bob", Age = 35 }
        };

        Console.WriteLine("Original List:");
        foreach (var person in people) { Console.WriteLine($"{person.Name}: {person.Age}"); }

        people.Sort(new AgeComparer());

        Console.WriteLine("\nSorted List by Age (List.Sort with IComparer):");
        foreach (var person in people) { Console.WriteLine($"{person.Name}: {person.Age}"); }

        //Using LINQ OrderBy with custom sorting
        people.Sort((p1, p2) => p1.Name.CompareTo(p2.Name)); //Sort by Name using lambda
        Console.WriteLine("\nSorted List by Name (List.Sort with Lambda):");
        foreach (var person in people) { Console.WriteLine($"{person.Name}: {person.Age}"); }

    }
}

Sorting with Custom Comparer using LINQ

LINQ's OrderBy can directly take a lambda expression that defines the property to sort by. This approach is concise and readable for simple sorting criteria.

using System;
using System.Collections.Generic;
using System.Linq;

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

public class Example
{
    public static void Main(string[] args)
    {
        List<Person> people = new List<Person>
        {
            new Person { Name = "Charlie", Age = 30 },
            new Person { Name = "Alice", Age = 25 },
            new Person { Name = "Bob", Age = 35 }
        };

        Console.WriteLine("Original List:");
        foreach (var person in people) { Console.WriteLine($"{person.Name}: {person.Age}"); }

        IEnumerable<Person> sortedPeopleByAge = people.OrderBy(person => person.Age);

        Console.WriteLine("\nSorted List by Age (LINQ OrderBy):");
        foreach (var person in sortedPeopleByAge) { Console.WriteLine($"{person.Name}: {person.Age}"); }

        IEnumerable<Person> sortedPeopleByName = people.OrderBy(person => person.Name);

        Console.WriteLine("\nSorted List by Name (LINQ OrderBy):");
        foreach (var person in sortedPeopleByName) { Console.WriteLine($"{person.Name}: {person.Age}"); }
    }
}

Concepts Behind the Snippet

The core concept behind sorting algorithms is comparing elements and rearranging them based on a defined order. Both List<T>.Sort() and LINQ OrderBy rely on comparers to determine the order of elements. List<T>.Sort() typically uses the IComparable implementation of the objects being sorted unless an IComparer implementation is provided.

Real-Life Use Case Section

Scenario: Sorting a list of products by price or name in an e-commerce application.

Imagine you have a list of product objects, each with properties like Name, Price, and Rating. You want to allow users to sort the products based on these criteria.

Example:

  • Sorting products by price (low to high or high to low) using OrderBy or OrderByDescending.
  • Sorting products alphabetically by name using OrderBy.
  • Sorting products by rating, potentially with a secondary sort by price for products with the same rating.

List<T>.Sort() would be suitable if you need to update the original list in place, while OrderBy is preferable if you want to display a sorted view of the data without modifying the underlying product list.

Best Practices

  • Choose the right method for the task: If you need to modify the original list, use List<T>.Sort(). If you need a new sorted collection, use LINQ OrderBy.
  • Use custom comparers when necessary: For complex sorting logic or when the default comparer is not sufficient, implement IComparer<T> or use a lambda expression.
  • Consider performance: List<T>.Sort() is generally faster for in-place sorting. LINQ OrderBy has the overhead of creating a new collection.
  • Avoid modifying the collection during enumeration: If you're using LINQ and need to iterate over the sorted result multiple times, consider converting it to a List or array using ToList() or ToArray() to avoid re-evaluation.

Interview Tip

Be prepared to discuss the differences between List<T>.Sort() and LINQ OrderBy, including their impact on the original collection and their performance characteristics. Also, be ready to explain how to implement custom comparers for more complex sorting scenarios.

A good answer would discuss in-place sorting versus creating a new collection, as well as the use of IComparer and lambda expressions.

When to use them

  • List<T>.Sort(): Use when you need to sort the original list directly and don't need to preserve the original order. It's also generally faster for in-place sorting.
  • LINQ OrderBy: Use when you need to create a new sorted collection without modifying the original list. It's also more flexible for complex sorting scenarios and can be chained with other LINQ methods. Use it when you want immutability.

Memory footprint

  • List<T>.Sort(): Has a lower memory footprint because it sorts the list in place.
  • LINQ OrderBy: Has a higher memory footprint because it creates a new collection to store the sorted result.

Alternatives

While List<T>.Sort() and LINQ OrderBy are the most common methods for sorting, other alternatives exist:

  • `Array.Sort()`: Sorts an array in place. Similar to List<T>.Sort() but for arrays.
  • Third-party sorting libraries: For very large datasets or specialized sorting requirements, consider using third-party libraries that offer optimized sorting algorithms.

Pros of `List.Sort()`

  • In-place sorting: Modifies the original list directly, saving memory.
  • Performance: Generally faster for in-place sorting compared to LINQ OrderBy.

Cons of `List.Sort()`

  • Modifies original list: Can be undesirable if you need to preserve the original order.
  • Less flexible: Not as flexible as LINQ OrderBy for complex sorting scenarios.

Pros of LINQ `OrderBy`

  • Does not modify original list: Preserves the original collection.
  • More flexible: Allows for complex sorting criteria using lambda expressions and can be chained with other LINQ methods.
  • Readability: Can improve code readability for complex sorting logic.

Cons of LINQ `OrderBy`

  • Performance: Can be slower than List<T>.Sort() due to the overhead of creating a new collection.
  • Memory footprint: Has a higher memory footprint because it creates a new collection.

FAQ

  • What's the difference between `List.Sort()` and LINQ `OrderBy`?

    List<T>.Sort() sorts the list in-place, modifying the original list directly, and is generally faster. LINQ OrderBy returns a new sorted IEnumerable<T>, leaving the original list unchanged, and provides more flexibility for complex sorting scenarios.

  • How do I sort a list of objects by a specific property?

    You can use either List<T>.Sort() with a custom IComparer<T> or LINQ OrderBy with a lambda expression that specifies the property to sort by.

  • Can I sort in descending order?

    Yes, you can use OrderByDescending in LINQ to sort in descending order. For List<T>.Sort(), you can implement a custom IComparer<T> that compares elements in reverse order.

  • Is it possible to sort a list of objects by multiple properties?

    Yes, using LINQ's ThenBy (and ThenByDescending) methods which allows you to specify secondary sorting criteria after the initial OrderBy or OrderByDescending. Alternatively, you can create a custom IComparer<T> that compares objects based on multiple properties.