Pregunta

Estoy escribiendo algunas extensiones para imitar el mapa y reducir funciones en 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);
}

La función de transformación reducirá cruft como:

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

¿Esto tiene sentido?¿Podría ser mejor?

¿Fue útil?

Solución

Estas ya se parecen mucho a las extensiones en Linq:

//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 */);

¿Por qué el segundo ejemplo se llama Transformar?¿Tiene la intención de cambiar los valores de la lista de alguna manera?Si ese es el caso, es mejor que utilices ConvertAll<T> o Select<T>.

Otros consejos

Según este enlace Programación funcional en C# 3.0:Cómo Mapa/Reducir/Filtro pueden sacudir tu mundo los siguientes son equivalentes en C# bajo el espacio de nombres System.Linq:

En su lugar, usaría los delegados Func integrados.Este mismo código funcionaría en cualquier IEnumerable.Tu código se convertiría en:

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);
}

Es posible que desee agregar una forma de hacer un mapa pero devolver una nueva lista, en lugar de trabajar en la lista pasada (y devolver la lista puede resultar útil para encadenar otras operaciones)...quizás una versión sobrecargada con un booleano que indica si desea devolver una nueva lista o no, como tal:

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;
}

Recomendaría crear métodos de extensión que utilicen LinQ internamente. como esto:

public static IEnumerable<R> Map<T, R>(this IEnumerable<T> self, Func<T, R> selector) {
    return self.Select(selector);
}

public static T Reduce<T>(this IEnumerable<T> self, Func<T, T, T> func) {
    return self.Aggregate(func);
}

public static IEnumerable<T> Filter<T>(this IEnumerable<T> self, Func<T, bool> predicate) {
    return self.Where(predicate);
}

Aquí algunos usos de ejemplo:

IEnumerable<string> myStrings = new List<string>() { "1", "2", "3", "4", "5" };
IEnumerable<int> convertedToInts = myStrings.Map(s => int.Parse(s));
IEnumerable<int> filteredInts = convertedToInts.Filter(i => i <= 3); // Keep 1,2,3
int sumOfAllInts = filteredInts.Reduce((sum, i) => sum + i); // Sum up all ints
Assert.Equal(6, sumOfAllInts); // 1+2+3 is 6

(Ver https://github.com/cs-util-com/cscore#ienumerable-extensions para más ejemplos)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top