Back to Blog
C#

C# Array Sorting: Array.Sort vs LINQ OrderBy

c# array sorting: Learn how to sort C# arrays with Array.Sort and LINQ OrderBy, including custom comparers and performance tradeoffs.

C#ArraySortingLINQComparerPerformance
Illustration of sorting an array of numbers in C# with ascending order.

c# array sorting requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

Sorting an array is a common operation in C#. The standard library provides two primary approaches: Array.Sort, which sorts the array in place, and LINQ's OrderBy, which returns a new sorted sequence. The choice between them affects memory usage, mutation behavior, and how you handle custom types. This article covers the syntax, behavior, and tradeoffs of each approach so you can pick the right one for your scenario.

Sorting an Array in Place with Array.Sort

The Array.Sort method sorts the elements of an array directly, modifying the original array. For a simple array of numeric or string types, the default comparer is used.

int[] numbers = { 5, 2, 8, 1, 9 }; Array.Sort(numbers); // numbers is now { 1, 2, 5, 8, 9 }

Array.Sort works on any array whose elements implement IComparable or IComparable<T>. For primitive types like int, double, and string, the default ordering is ascending, using the culture-invariant comparison for strings. The method has overloads that accept a range, a custom comparer, or a Comparison<T> delegate.

Because the sort happens in place, no new array is allocated. This is useful when you want to avoid extra memory usage and the original array no longer needs to be preserved. However, it also means the original order is lost, which may not be acceptable in all situations.

Sorting Without Mutating the Original Array with LINQ OrderBy

If you need to keep the original array unchanged, use LINQ's OrderBy method. OrderBy returns an IOrderedEnumerable<T> that you can materialize into a new array with ToArray().

int[] numbers = { 5, 2, 8, 1, 9 }; int[] sorted = numbers.OrderBy(n => n).ToArray(); // numbers remains { 5, 2, 8, 1, 9 } // sorted is { 1, 2, 5, 8, 9 }

OrderBy performs a stable sort, meaning that elements with equal keys retain their original relative order. This is different from Array.Sort, which is not guaranteed to be stable. The LINQ approach also works with any IEnumerable<T>, so you can sort a List<T> or any other sequence without converting to an array first.

The cost is that OrderBy allocates a new collection and has more overhead due to the iterator and delegate invocation. For large arrays, the extra memory allocation and CPU time can be significant, especially if you only need the sorted result once.

Custom Sorting with IComparer and Comparison Delegates

Both Array.Sort and LINQ's OrderBy support custom sorting logic. For Array.Sort, you can pass an IComparer<T> implementation or a Comparison<T> delegate.

string[] words = { "banana", "Apple", "cherry" }; Array.Sort(words, StringComparer.OrdinalIgnoreCase); // words is { "Apple", "banana", "cherry" }

For LINQ, use the OrderBy overload that accepts an IComparer<T>:

string[] words = { "banana", "Apple", "cherry" }; string[] sorted = words.OrderBy(w => w, StringComparer.OrdinalIgnoreCase).ToArray();

When you need a one-off comparison that doesn't warrant a full comparer class, a Comparison<T> delegate is concise:

int[] numbers = { 5, 2, 8, 1, 9 }; Array.Sort(numbers, (a, b) => b.CompareTo(a)); // descending

Custom comparers give you control over ordering rules, such as case-insensitive string comparison, culture-specific sorting, or sorting by a property of a custom type.

Sorting Arrays of Custom Types

For custom classes, you can either implement IComparable<T> on the type itself or provide a separate comparer. Implementing IComparable<T> makes the default Array.Sort work without extra arguments.

public class Person : IComparable<Person> { public string Name { get; set; } public int Age { get; set; } public int CompareTo(Person? other) { if (other is null) return 1; return Age.CompareTo(other.Age); } } Person[] people = { new Person { Name = "Alice", Age = 30 }, new Person { Name = "Bob", Age = 25 } }; Array.Sort(people); // Sorted by Age ascending

If you don't want to modify the class, use a custom comparer. This is often cleaner when the sort order varies by context.

public class PersonNameComparer : IComparer<Person> { public int Compare(Person? x, Person? y) { if (x is null && y is null) return 0; if (x is null) return -1; if (y is null) return 1; return string.Compare(x.Name, y.Name, StringComparison.Ordinal); } } Array.Sort(people, new PersonNameComparer());

For LINQ, the same comparer works with OrderBy:

Person[] sortedPeople = people.OrderBy(p => p, new PersonNameComparer()).ToArray();

Performance and Memory Considerations

The most important difference between Array.Sort and OrderBy is mutation and memory. Array.Sort sorts in place and uses an introspective sort algorithm (introsort), which is a hybrid of quicksort, heapsort, and insertion sort. It has an average and worst-case complexity of O(n log n). Because it operates directly on the array, it avoids allocating a new collection.

OrderBy uses a stable quicksort-like algorithm and returns a new sequence. It allocates memory for the new array and incurs overhead from the LINQ iterator and delegate calls. For small arrays, the difference is negligible, but for large arrays or performance-critical paths, Array.Sort is generally faster and uses less memory.

Another consideration is stability. If you need a stable sort (where equal elements keep their original order), OrderBy is the safer choice. Array.Sort is not stable, so equal elements may be reordered arbitrarily. If stability matters, either use OrderBy or manually add a secondary sort key.

Choosing the Right Sorting Approach for Your Scenario

Use Array.Sort when you want to sort the array in place, you don't need the original order afterward, and you want minimal memory overhead. This is typical for local arrays that are processed and then discarded.

Use LINQ OrderBy when you need to preserve the original array, when you're working with a non-array sequence like a List<T> or an IEnumerable<T>, or when you need a stable sort. The extra allocation is acceptable for moderate-sized collections or when the sorted result is needed only once.

For custom types, prefer implementing IComparable<T> if there is a single natural ordering. Use a custom comparer when multiple sort orders exist or when you want to keep the type simple. In performance-sensitive code, avoid LINQ in tight loops; instead, use Array.Sort with a comparer or a Comparison<T> delegate.

One edge case to watch is sorting arrays of nullable types. Array.Sort places nulls first by default, while OrderBy treats null as the default value for the type, which may differ. If you need consistent null handling, provide an explicit comparer that defines how nulls are ordered.

Understanding these tradeoffs lets you write C# array sorting code that is both correct and efficient for your specific use case.