Today, I want to take a brief detour from our excursions into C# 2.0 and
examine the C# 3.0 example from my
recent article on higher-order functions:
static void Main()
{
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
int sum = numbers.Filter(x => (x % 2) == 0).Map(x => x * x).Reduce(0, (x, y) => x + y);
Console.WriteLine("Sum: {0}", sum);
}
The calculation being performed (summing the squares of the even numbers in
an array) is not complicated, but I want to clarify that we don't actually have
to define Filter, Map and Reduce in C# 3.0. While those names might be familiar
to functional programmers, they already have equivalents in the .NET Framework
3.5.
- Filter = Where
- Map = Select
- Reduce = Aggregate
Each of these are implemented as extension methods for IEnumerable<T>. So, we
can rewrite the code like this:
static void Main()
{
var numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
var sum = numbers.Where(x
=> (x % 2) == 0).Select(x => x * x).Aggregate(0, (x, y) => x + y);
Console.WriteLine("Sum: {0}", sum);
}
The Aggregate method is a powerful way to create custom accumulations from an
IEnumerable<T>. However, the .NET Framework 3.5 also provides several methods
for common accumulations (e.g. Sum, Average, Count, Min, Max). In this
situation, we could just use the Sum method.
static void Main()
{
var numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
var sum = numbers.Where(x
=> (x % 2) == 0).Select(x => x * x).Sum();
Console.WriteLine("Sum: {0}", sum);
}
Finally, C# 3.0 provides a natural way to express the Where and Select calls
using a query expression.
static void Main()
{
var numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
var sum = (from n in numbers
where (n % 2) == 0
select n * n).Sum();
Console.WriteLine("Sum: {0}", sum);
}
While defining Filter, Map and Reduce are useful in C# 2.0, they are
redundant in C# 3.0. We can use features already present instead of reinventing
the wheel.
Have fun!