Know your LINQ- Enumerable Select Method

The “Select” method is a great one to learn first when you are getting into LINQ (Language Integrated Query). It’s one of the simpler ones to understand, among those which take parameters. And its usage is very common.

From the Microsoft Documents page

I love the description they give here, which I highlighted in yellow- it’s succinct and spot on. Select allows you to transform each element in your enumerable collection (array, list, etc.). The “Select” name seems like an odd choice at first given this behavior, but it comes from common syntax for accessing SQL databases. Note that you can transform your collection values to a new type or stay with the same type. So if you had a bunch of integers, you could make strings out of them or you could square them and they remain integers.

Notice there are two overloads for this method. Recall that method overloads are when there are multiple versions of a method, with the same name, but whose parameter lists are different. You’ll see above that the difference here is that one overload has an additional Int32 (32 bit integer) parameter which represents each element’s index position within the collection. This is pretty cool, it means you don’t need to use a traditional “for” loop when you need access to element indices.

Notice the Namespace value in the image above: System.Linq. So you need to include a “using System.Linq” line in your code file if you want access to this (and the other) LINQ methods. Let’s look at one of the method overloads in more detail:

Notice that this is an extension method, evidenced by the highlighted “this” keyword that precedes the first parameter. I tell beginners to not even think of this “source” parameter as a parameter. It rather specifies the type that you may call the Select method on- in this case a collection that implements the IEnumerable interface. Many of the collections you use implement this interface, whether you realized it or not. Since this “parameter” is generic, we can use it with any type we want. They generally refer to the generic type as “TSource” because they couldn’t list every possible type. So while it may look funny at first, it makes a lot of sense and is the easiest way of expressing the situation.

Then for the “real” parameter, we see it is a function delegate. The signature specifies that it should take a function that accepts one parameter of type TSource and returns some type referred to as TResult. Note that TSource and TResult may be the same type, but often they are not. They are given different names because it is not required they are of the same type. We often drop lambda expressions in for this parameter.

Not shown in the image above, but on the docs page is the return type. Notice that an IEnumerable (collection) of type TResult is returned by the Select method. Hopefully you see the connection now. You originally have some source of objects, say integers. You provide a function that specifies how to get from an object of the source type to an object of the result type. This function can be thought of then as converting the input to an output of some form, possibly different. And the Select method returns a collection of the same size, but of the result type. So Select is like a loop that goes over all your elements and uses a function you provide to process each element, then returns you a collection of corresponding outputs for each source element.

My comments here are largely applicable to the other overload too:

This overload allows you to access each element’s index position within the collection.

You can see I highlighted the difference- the “int” type in the function delegate parameters. This new delegate specifies it needs a function with two parameters now, a TSource type first, then an integer (the last one is always the return type). Remember TSource could be anything, so it could be an integer too. When you insert your lambda expression for this parameter, you’ll be able to access this second integer parameter of your lambda to get the positional value of each element you encounter from the source collection. So you don’t need to use a “for” loop to work with index values, which is very convenient.

The docs page offers some clear examples of usage like this:

You may see countless other examples in the coding challenge videos on my YouTube channel.

Previous
Previous

The StringBuilder Class: An Alternative to Using Strings

Next
Next

A Simpler Way to Think About the “static” Keyword