Me old mucker Spencer pointed out today that C# 3’s newly-refurbished IEnumerable<T> class lacks some basic features. Specifically, it lacks equivalents for the classic Map, Filter, and Reduce functions seen in functional languages. The first two are familiar as List<T>.ConvertAll, and List<T>.FindAll. The third isn’t so familiar, but is still very useful. I’ve also thrown in an implementation of ForEach for free.
[Ben Hall](http://blog.benhall.me.uk/2007/08/converting-ienumerable-to-ienumerable.html) points out that it’s possible to extend the class, but I wanted to get a full, commented implementation of the three functions. Feel free to use this code in your own work.
So, here they are;
IEnumerableExtras
——
public static class IEnumerableExtras
{
///
///
/// The source type
/// the IEnum
/// the action to perform.
public static void ForEach
(this IEnumerable list, Action action)
{
foreach (T item in list) { action(item); }
}
///
/// function
///
/// The source type
/// The destination type
/// the list to convert
/// a function to convert
/// one item to another.
/// all items in the list converted by
/// the converter function.
public static IEnumerable Map
(this IEnumerable list, Converter converter)
{
foreach (T item in list)
{
yield return converter(item);
}
}
///
/// elements which return true from ‘condition’.
///
/// The source type
/// the list to filter
/// the ‘keep in’ condition
/// the items for which condition(item)
/// is true
public static IEnumerable Filter
(this IEnumerable list, Predicate condition)
{
foreach (T item in list)
{
if (condition(item))
{
yield return item;
}
}
}
///
/// used to, say, sum a list of integers, or
/// concatenate a number of strings, or find the
/// maximum value in a collection.
///
///
///
///
///
public static T Reduce
(this IEnumerable list, Func reducer)
{
IEnumerator enumerator = list.GetEnumerator();
if (enumerator.MoveNext())
{
// we have some items; start combining them together.
T aggregator = enumerator.Current;
while (enumerator.MoveNext())
{
aggregator = reducer(aggregator,
enumerator.Current);
}
return aggregator;
}
else
{
// there was nothing in the list; return default.
return default(T);
}
}
}
And here’s an **example program**;
static void Main(string[] args)
{
IEnumerable maybeDoubles =
new List {1, 2, null, 3, 4, null, null, null};
// remove all the empty values: [1,2,3,4]
IEnumerable noNulls = maybeDoubles.Filter(x => x.HasValue);
// convert Nullable to non-nullable: >[1,2,3,4]
IEnumerable notNullable = noNulls.Map(x => x.Value);
// convert to strings so we can display them. [“1”, “2”, “3”, “4”]
IEnumerable stringVersions = notNullable.Map(x=>x.ToString());
// join the strings together with commas “1, 2, 3, 4”
string displayString = stringVersions.Reduce( (s1, s2) => s1 + “, ” + s2);
// show us the result;
Console.WriteLine(displayString);
Console.ReadLine();
}
So there you go. Enjoy.
4 responses to “C# Coding; Missing Functions on IEnumerable”
Your Filter method is just the same as Where which is already in LINQ, and the Map method is just the same as Select 😉
Oh and Reduce is Aggregate, the code is exactly the same 😛
Hi! The LINQ libraries aren’t available if, like me, you’re deploying to .net 2.0 but using C#3. So I didn’t know. Thanks for the pointer!
[…] you need a LINQ-free version for backward compatibility, check out Missing Functions on IEnumerable on Steve Cooper’s […]