Back to Blog
C#

How to Reverse a List in C#: In-Place and LINQ

c# list reverse: Learn how to reverse a List in C# using List.Reverse() and LINQ's Reverse(), including performance tradeoffs and when to use each.

C#ListLINQCollectionsPerformance
Illustration of reversing the order of elements in a C# List, showing in-place and LINQ approaches.

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

Reversing the order of elements in a List<T> is a common operation in C#. The language provides two primary approaches: the instance method List<T>.Reverse() and the LINQ extension method Enumerable.Reverse(). They differ in whether they modify the original list or produce a new sequence, and that difference drives most practical decisions.

The Built-in List.Reverse() Method

The List<T> class has a parameterless Reverse() method that reverses the order of all elements in place. It modifies the existing list and returns void. This is the most direct way to reverse a list when you no longer need the original order.

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 }; numbers.Reverse(); // numbers is now { 5, 4, 3, 2, 1 }

The method operates on the underlying array of the list, swapping elements from both ends until it reaches the middle. Because it works in place, it does not allocate a new list or create additional references to the elements. This makes it memory-efficient for large lists.

There is also an overload Reverse(int index, int count) that reverses a specific range. This is useful when you only need to reorder a portion of the list.

List<string> words = new List<string> { "a", "b", "c", "d", "e" }; words.Reverse(1, 3); // reverses elements at indexes 1, 2, 3 // words is now { "a", "d", "c", "b", "e" }

The range overload is efficient because it only swaps the specified elements. It also validates that index and count describe a valid range, throwing ArgumentOutOfRangeException if they do not.

Reversing with LINQ's Reverse() Extension

If you prefer a functional style or need to keep the original list unchanged, use the LINQ extension method Enumerable.Reverse(). It is available in the System.Linq namespace and works on any IEnumerable<T>, including List<T>.

using System.Linq; List<int> original = new List<int> { 1, 2, 3, 4, 5 }; IEnumerable<int> reversed = original.Reverse(); // original is still { 1, 2, 3, 4, 5 } // reversed yields 5, 4, 3, 2, 1 when enumerated

Reverse() returns a deferred sequence. It does not copy the elements immediately; it only iterates the source in reverse order when you enumerate the result. This means you can chain it with other LINQ operations without materializing an intermediate list.

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 }; var firstThreeReversed = numbers.Reverse().Take(3).ToList(); // firstThreeReversed is { 5, 4, 3 }

Because the result is an IEnumerable<T>, you can call ToList() or ToArray() if you need a concrete collection. Be aware that each enumeration of the reversed sequence re-walks the original list, so if you enumerate it multiple times, the source list must remain unchanged between iterations.

In-Place vs. Creating a New List

The choice between List.Reverse() and LINQ's Reverse() often comes down to whether you want to mutate the original collection. In-place reversal is useful when the list is a local variable or when you want to avoid the overhead of creating a new list. It also preserves the same list reference, which matters if other code holds a reference to that instance.

Creating a new list with LINQ is preferable when you need to keep the original order for later use, or when you want to pass the reversed result to a method without affecting the caller's data. It also works with interfaces like IEnumerable<T> or IReadOnlyList<T>, where the List<T>.Reverse() method is not available.

Consider this example where the original list must remain intact:

List<int> source = new List<int> { 1, 2, 3 }; List<int> reversedCopy = source.Reverse().ToList(); // source remains { 1, 2, 3 } // reversedCopy is { 3, 2, 1 }

If you only need to iterate in reverse once, you can avoid materializing the list entirely by using Reverse() directly in a foreach loop. This saves memory and can be more efficient when the source list is large and you only need a few elements from the end.

Performance and Memory Considerations

The performance characteristics of the two approaches differ significantly. List<T>.Reverse() runs in O(n) time and uses O(1) extra space because it swaps elements in place. It is the fastest option when you can modify the original list.

LINQ's Reverse() is also O(n) in terms of iteration time, but it uses an iterator that stores the elements internally when you start enumerating. The first call to MoveNext() on the reversed sequence copies the entire source into an array so it can iterate backward. This means the first enumeration allocates O(n) memory. Subsequent enumerations of the same reversed sequence allocate again because the iterator is recreated each time you call GetEnumerator().

If you need a reversed copy, calling Reverse().ToList() allocates a new list and copies all elements, which is O(n) memory. In contrast, List.Reverse() does not allocate any new list, so it is more memory-efficient when the original order is not needed.

For very large lists, in-place reversal avoids a second large allocation. However, if you need the original list for other operations, the allocation cost of a copy may be acceptable. In high-throughput scenarios, measure the impact of both approaches on your specific data sizes rather than assuming one is always better.

Reversing a Slice or Range

The List<T>.Reverse(int index, int count) overload is the only built-in way to reverse a portion of a list in place. It is useful for algorithms that require partial reordering, such as rotating a list or implementing certain sorting steps.

List<char> chars = new List<char> { 'a', 'b', 'c', 'd', 'e', 'f' }; chars.Reverse(2, 3); // reverse 'c', 'd', 'e' // chars is now { 'a', 'b', 'e', 'd', 'c', 'f' }

LINQ does not have a built-in Reverse for a range, but you can combine Skip() and Take() to create a reversed subsequence. This produces a new sequence rather than modifying the original.

List<int> nums = new List<int> { 1, 2, 3, 4, 5, 6 }; var reversedMiddle = nums.Skip(2).Take(3).Reverse().ToList(); // reversedMiddle is { 5, 4, 3 }

The LINQ approach does not modify nums, and it allocates a new list for the result. If you need to modify the original list in place, use the range overload of List.Reverse().

Common Mistakes and Edge Cases

One frequent mistake is assuming that List.Reverse() returns a new list. It returns void, so code like var reversed = myList.Reverse(); will not compile. Always call it as a statement, not as an assignment.

Another edge case is reversing an empty list or a list with a single element. Both methods handle these gracefully: List.Reverse() does nothing, and LINQ's Reverse() yields an empty or single-element sequence. No exception is thrown.

When using the range overload, ensure that index and count are valid. Passing a negative index or a count that exceeds the list length throws ArgumentOutOfRangeException. For example, list.Reverse(0, list.Count + 1) will fail.

If you are working with a custom type that implements IList<T> but not List<T>, you cannot call List.Reverse() directly. You can either cast to List<T> if the underlying object is indeed a List<T>, or use LINQ's Reverse() to get a reversed sequence. The LINQ approach is more general because it works on any IEnumerable<T>.

Choosing the Right Approach for Your Scenario

The decision between in-place and LINQ reversal depends on your data flow and ownership requirements. Use List<T>.Reverse() when:

  • You own the list and no other code depends on its original order.
  • You want to avoid allocating a new list, especially for large collections.
  • You need to reverse a specific range in place.

Use LINQ's Reverse() when:

  • You must preserve the original list for later use.
  • You are working with an interface like IEnumerable<T> or IReadOnlyList<T>.
  • You want to chain the reversed sequence with other LINQ operations without materializing an intermediate list.

In performance-sensitive paths, the allocation behavior is the main differentiator. In-place reversal has zero extra memory cost, while LINQ's deferred implementation allocates an array on first enumeration. If you only need to iterate the reversed sequence once, the allocation may be acceptable. If you need to keep a reversed copy, Reverse().ToList() is straightforward but costs memory proportional to the list size.

For most application code, clarity matters more than micro-optimizations. Choose the approach that expresses your intent most clearly. If you are reversing a list to display it in descending order, LINQ's Reverse() on an already-sorted list is readable. If you are implementing an algorithm that requires in-place mutation, use List.Reverse(). The two methods are not interchangeable in all contexts, so understanding the difference prevents subtle bugs.

c# list reverse: Practical Usage and Code Examples | RYUSLOG DEV