views:

1949

answers:

6

I am writing a few extensions to mimic the map and reduce functions in Lisp.

public delegate R ReduceFunction<T,R>(T t, R previous);
public delegate void TransformFunction<T>(T t, params object[] args);

public static R Reduce<T,R>(this List<T> list, ReduceFunction<T,R> r, R initial)
{
     var aggregate = initial;
     foreach(var t in list)
         aggregate = r(t,aggregate);

     return aggregate;
}
public static void Transform<T>(this List<T> list, TransformFunction<T> f, params object [] args)
{
    foreach(var t in list)
         f(t,args);
}

The transform function will cut down on cruft like:

foreach(var t in list)
    if(conditions && moreconditions)
        //do work etc

Does this make sense? Could it be better?

+2  A: 

I would use the built in Func delegates instead. This same code would work on any IEnumerable. Your code would turn into:

public static R Reduce<T,R>(this IEnumerable<T> list, Func<T,R> r, R initial)
{
  var aggregate = initial;
  foreach(var t in list)
   aggregate = r(t,aggregate);

  return aggregate;
}
public static void Transform<T>(this IEnumerable<T> list, Func<T> f)
{
 foreach(var t in list)
          f(t);
}
Jake Pearson
+1  A: 

You might want to add a way to do a map but return a new list, instead of working on the list passed in (and returning the list can prove useful to chain other operations)... perhaps an overloaded version with a boolean that indicates if you want to return a new list or not, as such:

public static List<T> Transform<T>(this List<T> list, TransformFunction<T> f,
        params object [] args)
{
    return Transform(list, f, false, args);
}

public static List<T> Transform<T>(this List<T> list, TransformFunction<T> f,
        bool create, params object [] args)
{
    // Add code to create if create is true (sorry,
    // too lazy to actually code this up)
    foreach(var t in list)
         f(t,args);
    return list;
}
Mike Stone
A: 

@ Mike Stone You might want to add a way to do a map but return a new list, instead of working on the list passed in

I like the idea of not changing the list in Transform but the intention there was to modify the list and objects in place. It is definitely a a good idea to offer a way to not change them though. I wish I could accept both answers!

kazakdogofspace
+8  A: 

These look very similar to extensions in Linq already:

//takes a function that matches the Func<T,R> delegate
listInstance.Aggregate( 
    startingValue, 
    (x, y) => /* aggregate two subsequent values */ );

//takes a function that matches the Action<T> delegate
listInstance.ForEach( 
    x => /* do something with x */);

Why is the 2nd example called Transform? Do you intend to change the values in the list somehow? If that's the case you may be better off using ConvertAll<T> or Select<T>.

Keith
A: 

@Keith Thanks for stopping me from reinventing the wheel!

kazakdogofspace
+4  A: 

According to this link Functional Programming in C# 3.0: How Map/Reduce/Filter can Rock your World the following are the equivalent in C# under the System.Linq namespace:

Ray Vega