I recently came across an article on Joel Hooks' blog about using the underscore.js library to avoid writing for loops in JavaScript code. I haven't written any JavaScript in years, but I figured it ought to be possible to take the challenge in .NET too.
To get a bit of practice, I picked some of my old code at random, and searched through it for the for loops, to see if I could eliminate all of them. I've changed class and method names to make the points clearer.
Simple extraction
First up, using a for loop to extract a subset of a collection:
var dogs = new List<Animal>(); foreach (var animal in animals.Where(animal=>animal.IsDog)) { dogs.Add(animal); }
Always nice to start with an easy one:
var dogs = animals.Where(animal => animal.IsDog).ToList();
Initialisation
Next, a loop used to initialise some objects in a collection:
foreach (var animal in animals) { animal.IsHungry = false; animal.LastVetVisit = DateTime.Now; }
Again, eliminating the for loop is simple:
animals.ForEach(animal => Initialise(animal)); ... private static void Initialise(Animal animal) { animal.IsHungry = false; animal.LastVetVisit = DateTime.Now; }
In fact, we can just write this:
animals.ForEach(Initialise);
Or, if the method is very simple, just use an anonymous method instead:
animals.ForEach(animal => { animal.IsHungry = false; animal.LastVetVisit = DateTime.Now; });
That said, since the primary purpose of replacing the for loops is to make the code easier to read, I'd be inclined to use a separate method with a well-chosen name for anything other than a single line of code.
Inspection
Next, using a loop to set a flag based on the contents of a collection:
bool hasHungryOffspring = false; foreach (var offspring in animal.Offspring) { if (offspring.IsHungry) { hasHungryOffspring = true; break; } }
This is simple too:
var hasHungryOffspring = animal.Offspring.Any(a => a.IsHungry);
Extraction over a hierarchy
Okay, let's try something a bit more tricky. Suppose we want to get a list of all animals with no offspring. Further, let's suppose we're just interested in the animals in our list or their direct offspring, so there's no need to get into any recursion. Here's my original code:
var animalsWithNoOffspring = new List<Animal>(); foreach (var animal in animals) { if (animal.Offspring.Any()) { animalsWithNoOffspring.AddRange( animal.Offspring.Where(a => !a.Offspring.Any())); } else { animalsWithNoOffspring.Add(animal); } }
The key to removing the for loop this time is to recognise that we just need to flatten all animals into a single list, then pick the ones that have no offspring. The SelectMany function helps us do this:
var animalsWithNoOffspring = animals.Union(animals.SelectMany(a => a.Offspring)) .Where(a => !a.Offspring.Any());
Dictionary creation
Okay, what about the situation where you want to create a Dictionary from a collection? So, for example, suppose we want a Dictionary whose key is the type of the animal and whose value is a list of all the animals of that type. Here's how I originally did it:
var animalsByType = new Dictionary<Type, List<Animal>>(); foreach (var animal in animals) { if (!animalsByType.ContainsKey(animal.GetType())) { var animalsOfType = new List(); animalsByType[animal.GetType()] = animalsOfType; } animalsByType[animal.GetType()].Add(animal); }
Surely we need the for loop here?
Well, no. No, we don't:
var animalsByType = animals.GroupBy(a => a.GetType()) .ToDictionary( group => group.Key, group => group.ToList() );
We use the GroupBy function to put our animals into groups according to their type, then the ToDictionary function to convert those groups into a Dictionary using the group key (in this case, the animal's Type) as the Dictionary's key and the group values (the Animal objects), converted to a List, as the Dictionary values.
Writing loops in .NET starts to feel like using cursors in SQL - something that can usually be avoided.
So next time you catch yourself starting to type "for...", stop and ask yourself if you could make your code shorter and clearer by using a different construct instead.