LINQ gems: Indexed Select

Here's another LINQ gem, which is very useful if you plan to base your projection or filtering logic on the element's index in a sequence.

From the MSDN page for Enumerable.Select():

Projects each element of a sequence into a new form by incorporating the element's index.

What the "incorporating the element's index" part means is that you get an extra parameter inside of the Select method's selector, which gets incremented with each processed element. As is common in C#, the index is zero-based.

Example

Let's have a look at a simple example, which outputs the sequence numbers of days in a week (apologies to all readers, for whom Monday is not the first day of the week 😊).

var days = new[] { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
var daysOutput = days.Select((day, index) => 
    $"{day} is day number: {(index + 1)}").ToList();
daysOutput.ForEach(output => Console.WriteLine(output));

When executed, the output will be the following:

Mon is day number: 1
Tue is day number: 2
Wed is day number: 3
Thu is day number: 4
Fri is day number: 5
Sat is day number: 6
Sun is day number: 7

or...

Let's just simply generate a sequence number for an array of values and project it into an array for whatever usage may be appropriate.

var days = new[] { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
var indexedDays = days.Select((day, index) => 
    new { Day = day, Index = index }).ToArray();

How about query expression syntax?

There is no query expression syntax for this overload of the Select method. However, one can simply embed the indexed Select overload inside of the query expression:

var days = new[] { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
var weekendDays = 
    from day in days.Select((day, index) => new { day, num = index + 1 })
    where day.num >= 6
    select day.day;

Enumerable.Where()

There is an indexed overload available for the Enumerable.Where() extension method too. Using Where instead of Select, the previous example can be further simplified:

var days = new[] { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
var weekendDays = days.Where((day, index) => index >= 5); // (index+1) >= 6

Other useful applications

  • Selecting each N-th element in a sequence

  • Ordering based on element position

  • Coordination across multiple sequences


If you find this post interesting, be sure to check out my other posts in the LINQ gems series.

Comments (2)

Deivydas Voroneckis's photo

Would this work in Ef Core non client query evaluation?

Jan Doubek's photo

Good question. Even though there is an indexed Queryable.Select() overload, I do not think EF Core (or at least the EF SQL Server provider) actually supports it. I checked it real quick and got a "LINQ expression could not be translated" exception.