Introduction
I’ve mentioned the Reverse method a couple of times now, so I feel it deserved it’s own post, comparing and contrasting the various implementations.
Most recently it came up in one of my technical interviews, and knowing it existed ultimately helped me to land the job, so I want to share this wonderful Linq extension method with you all. Let’s start with an example:
Example:
Given an array of strings, print them all in reverse order.
using System; using System.Linq; public class Program { public static void Main() { var numbers = new int[] {1, 2, 3}; foreach(var number in numbers.Reverse()) { Console.WriteLine(number); } } } /* this code outputs: 3 2 1 */
This is a fairly straightforward example, but what’s going on here?
Well, the line: “foreach(var number in numbers.Reverse())” is the interesting one, this causes use to iterate over the array in reverse order. Importantly it uses my favoured Linq Reverse extension method.
Does this create a copy of the array? this stack overflow answer suggest that yes, it does. The reason being that changing this behaviour might break existing code that modifies the collection it’s iterating over.
Certainly there are some cases (i.e. IEnumerables of unknown size) where it’s necessary to loop through and reach the end of the collection before we can start reversing it.
But I still prefer it because it sticks to functional programming principles of not mutating/changing the original dataset. It’s also very handy because you can chain the calls.
List Reverse (without Linq)
Consider the following (non-functional) example which does mutate the original datastructure:
using System; using System.Collections.Generic; public class Program { public static void Main() { var numbers = new List<int>() {1, 2, 3}; numbers.Reverse(); foreach(var number in numbers) { Console.WriteLine(number); } } } /* this code outputs: 3 2 1 */
The difference here is subtle, but note that we’re not using System.Linq.
This is an older (pre-Linq) method for reversing a list and we lose the original (un-reversed) data. This change has come about because we’ve switched from using an Array to using a List and (unlike Array) List had it’s own .Reverse() implementation before the Linq extension method was introduced.
So how do we use the newer (and better?) Linq extension method with a list?
Using Linq Reverse with a List with Enumerable.Reverse(ourList)
To use the Linq extension method on a List we need to call it explicitly using Enumerable.Reverse():
using System; using System.Collections.Generic; using System.Linq; public class Program { public static void Main() { var numbers = new List<int>() {1, 2, 3}; foreach(var number in Enumerable.Reverse(numbers)) { Console.WriteLine(number); } Console.WriteLine(); Console.WriteLine("We still have access to the original list:"); foreach(var number in numbers) { Console.WriteLine(number); } } } /* this code outputs: 3 2 1 We still have access to the original list: 1 2 3 */
Array.Reverse vs Linq Reverse for Arrays
The first example used an array and it defaulted to Linq, while the second example used a List but it had a Reverse implementation which pre-dated Linq. But hang on, Arrays are much older than Linq, why don’t they have a Reverse implementation?
It turns out there is a non-functional (reverse in place) reverse method for Arrays, it’s just accessed as a static method on Array:
using System; public class Program { public static void Main() { var numbers = new int[] {1, 2, 3}; Array.Reverse(numbers); foreach(var number in numbers) { Console.WriteLine(number); } } } /* this code outputs: 3 2 1 */
Conclusion
We’ve seen that the .Reverse() Linq method is great, it doesn’t mutate the underlying data and is very handy for iterating backwards through a collection.
We have to be careful when using Lists however, as they have their own .Reverse which behaves differently.
We can call Enumerable.Reverse(ourList) to get the modern functional behaviour with lists.
At some point I’ll do a deep dive on Functional style programming in C#, but until then, you might like to check out some more details on my recent Linq Interview questions (including the one using Reverse): Linq Interview Questions – How to prepare for an interview by example.