Using Indexes With LINQ
[C#, LINQ, .NET]
A common algorithmic challenge you will probably run into is having a collection of items and then, for whatever reason, requiring the index of each item relative to the others in the collection.
For example, take this collection:
string[] names =
[
"Brenda", "Latisha", "Linda", "Felicia", "Dawn", "LeShaun", "Ines", "Alicia", "Teresa", "Monica", "Sharon", "Nicki",
"Lisa", "Veronica", "Karen", "Vicky", "Cookie", "Tonya", "Diane", "Lori", "Carla", "Marina", "Selena", "Katrina",
"Sabrina", "Kim", "LaToya", "Tina", "Shelley", "Bridget", "Cathy", "Rasheeda", "Kelly", "Nicole", "Angel",
"Juanita", "Stacy", "Tracie", "Rohna", "Ronda", "Donna", "Yolanda", "Tawana", "Wanda",
];
A quick way to get the index is as follows:
for (var i = 0; i < names.Length; i++)
{
Console.WriteLine($"{names[i]} is item {i}");
}
If we needed a list of every other name, we could do it like this:
var everyOtherName = new List<string>();
for (var i = 0; i < names.Length; i++)
{
if (i % 2 == 0)
everyOtherName.Add(names[i]);
}
everyOtherName.ForEach(Console.WriteLine);
There are several ways to solve the problem of accessing the index using LINQ.
The first is the Index method.
var namesWithIndexes = names.Index().ToList();
namesWithIndexes.ForEach(element =>
Console.WriteLine($"{element.Item} is index {element.Index}"));
For each item in the collection, Index
returns a Tuple of each item and its corresponding index. You can then use this Tuple
subsequently in your logic. You can view this Tuple
in the intellisense.
You can also use the Select method, which has an overload that allows access to the index.
var otherNamesWithIndexes = names.Select((element, index) =>
new { Name = element, Index = index }).ToList();
otherNamesWithIndexes.ForEach(element =>
Console.WriteLine($"{element.Name} is index {element.Index}"));
You can view this in the Intellisense.
A lesser-known fact is that the Where method also has an overload that allows you to access the index as well as specify your filter criteria.
This allows you to compose collections from some complicated scenarios.
Suppose we wanted to select all names with a length greater than five and then give an award to every other.
var filteredVictorious = names.Where((element, index) =>
// Filter names with length greater than 5 and then
// pick the even ones based on the modulus division of
// the index
element.Length > 5 && index % 2 == 0).ToList();
// Print to console
filteredVictorious.ForEach(Console.WriteLine);
Here, we use the Where
method and provide a function within which we leverage the collection element and its index for our logic.
This should print the following:
Brenda
Teresa
Sharon
Cookie
Selena
Sabrina
LaToya
TLDR
LINQ has several methods that allow you to access the index of items in your collection that you can leverage in your logic.
This is an update to this post I wrote earlier
The code is in my Github.
Happy hacking!