Question

J'écris quelques extensions pour imiter la carte et réduire les fonctions 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 fonction de transformation réduira les erreurs telles que :

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

Est-ce que ça a du sens?Est-ce que ça pourrait être mieux ?

Était-ce utile?

La solution

Celles-ci ressemblent déjà beaucoup aux extensions de 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 */);

Pourquoi le 2ème exemple s'appelle-t-il Transform ?Avez-vous l'intention de modifier les valeurs de la liste d'une manière ou d'une autre ?Si tel est le cas, vous feriez peut-être mieux d'utiliser ConvertAll<T> ou Select<T>.

Autres conseils

D'après ce lien Programmation fonctionnelle en C# 3.0 :Comment cartographier/réduire/filtrer peut bouleverser votre monde les éléments suivants sont l'équivalent en C# sous l'espace de noms System.Linq :

J'utiliserais plutôt les délégués Func intégrés.Ce même code fonctionnerait sur n’importe quel IEnumerable.Votre code se transformerait 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);
}

Vous souhaiterez peut-être ajouter un moyen de créer une carte mais renvoyer une nouvelle liste, au lieu de travailler sur la liste transmise (et renvoyer la liste peut s'avérer utile pour enchaîner d'autres opérations)...peut-être une version surchargée avec un booléen qui indique si vous souhaitez ou non renvoyer une nouvelle liste, en tant que telle :

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

Je recommanderais de créer des méthodes d'extension qui utilisent LinQ en interne comme ça:

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

Voici quelques exemples d'utilisations :

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

(Voir https://github.com/cs-util-com/cscore#ienumerable-extensions pour plus d'exemples)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top