C#: Refactoring to functional collection parameters
I wrote about a month or so ago about the functional collection parameters now available in C# and certainly one of the most fun refactorings for me is trying to get code written using a for loop into a state where it is using one of these.
With a bit of help from my colleague James Crisp, these are some of the most common refactorings that I have come across so far.
There’s a little bit of repetition with regards to my previous post but I think it’s interesting to see the procedural approach to solving this problems versus the functional approach.
For the sake of the examples, the following classes are common:
public class Foo
{
private String bar;
private String baz;
private readonly bool specialFlag;
public Foo(string bar, string baz, bool specialFlag)
{
this.bar = bar;
this.baz = baz;
this.specialFlag = specialFlag;
}
public bool HasSpecialFlag()
{
return specialFlag;
}
}
public class NewFoo
{
public NewFoo(Foo foo)
{
}
}
public class NumericFoo
{
public int Value { get; set; }
}
Going from one collection to another conditionally
var foos = new List<Foo> {new Foo("bar1", "baz2", true), new Foo("bar2", "baz2", false)}.Where(foo => foo.HasSpecialFlag());
var newFoos = new List<NewFoo>();
foreach (var foo in foos)
{
newFoos.Add(new NewFoo(foo));
}
We started off well using the 'Where' method to reduce the original list but we can do even better!
var foos = new List<Foo> {new Foo("bar1", "baz2", true), new Foo("bar2", "baz2", false)};
foos.Where(foo => foo.HasSpecialFlag())
.Select(foo => new NewFoo(foo));
Not significantly less code but it removes the need for more state in our code and makes the code more expressive at the same time which can only be a good thing.
Returning just one result
I came across some code last week which was iterating through a collection and then returning the first item which matched a certain criteria.
This would be useful if we wanted to get the first Foo object which has the special flag set for example.
private Foo GetSpecialFoo(List<Foo> foos)
{
foreach (var foo in foos)
{
if(foo.HasSpecialFlag())
{
return foo;
}
}
return null;
}
My initial thoughts on coming upon this code were that it should be possible to get rid of the loop but I wasn’t sure how to do the return. Luckily the 'First' method solves this problem.
private Foo GetSpecialFoo(List<Foo> foos)
{
return foos.Where(foo => foo.HasSpecialFlag()).First();
}
Accumulating some values
Adding values in collections together is surely one of the most common operations we do and functional collection parameters can help us here too.
var numericFoos = new List<NumericFoo> {new NumericFoo {Value = 2}, new NumericFoo {Value = 5}};
int total = 0;
foreach (var numericFoo in numericFoos)
{
total += numericFoo.Value;
}
Introducing a functional approach here gives us the following code:
var numericFoos = new List<NumericFoo> {new NumericFoo {Value = 2}, new NumericFoo {Value = 5}};
int total = numericFoos.Sum(foo => foo.Value);
About the author
I'm currently working on short form content at ClickHouse. I publish short 5 minute videos showing how to solve data problems on YouTube @LearnDataWithMark. I previously worked on graph analytics at Neo4j, where I also co-authored the O'Reilly Graph Algorithms Book with Amy Hodler.