Friday, December 6, 2019

Enumerating a Collection with an Index

There is often the case where you want to loop over a collection of objects along with an indicator of where you are in the loop. While some languages have a built-in syntax for expressing this C# does not (yet). Using a bit of LINQ you can easily accomplish this.

Normally starting with a collection of things you might use a for loop to iterate over list and provide your index.

For example:


 var items = new List<string>();

 for (int i = 0; i < items.Count; i++) {
  var item = items[i];
  Console.WriteLine($"Item {i}: {item}");
 }

You can also use a foreach and use an temp variable to track the index.


 int i = 0;
 foreach (var item in items) {
  Console.WriteLine($"Item {i}: {item}");
  i++;
 }

Recently I discovered this gem. The following code uses a Linq Select statement to transform the list into tuples containing the index and the object as named properties. Not quite as nice as if this was built-in to the language but still nice to be able to reduce the code down.


 foreach (var (item, index) in items.Select((v, i) => (v, i))) {
  Console.WriteLine($"Item {index}: {item}");
 }

You can also add an extension method to encapsulate the Select and make it a little cleaner.


  /// <summary>
  /// Return the list as an enumerable of tuples with the item and it's index in the list. 
  /// </summary>
  /// <typeparam name="T">The typeof items in the list</typeparam>
  /// <param name="list">List to converted</param>
  /// <returns>Enumerable of tuples with the item and it's index</returns>
  public static IEnumerable<(T, int)> WithIndex<T>(this IEnumerable<T> list) => 
    list.Select((value, index) => (value, index));

And then use it like this:


 foreach (var (item, index) in items.WithIndex()) {
  Console.WriteLine($"Item {index}: {item}");
 }

No comments: