2008-09-02 7 views
26

J'écris quelques extensions pour imiter la carte et réduire les fonctions en Lisp.Generic Map/Réduire les extensions de liste en C#

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éduire cochonneries comme:

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

Est-ce que ce sens? Pourrait-il être meilleur?

+2

Cela existe déjà. Jetez un oeil à C# 3/LINQ. – yfeldblum

+2

Oui, cela a du sens. Les réponses à cette question et à plusieurs autres montrent un * étonnant * manque de compréhension de ce qu'est une fonction de réduction. Oui, le type de sortie est supposé être indépendant du type d'entrée. 'Aggregate' n'est pas une fonction de réduction, comme beaucoup de gens l'ont prétendu. Peut-être que c'est pourquoi ils l'ont appelé quelque chose de différent. – harpo

Répondre

35

Ces très similaires aux extensions LINQ déjà:

//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 Transform? Avez-vous l'intention de changer les valeurs dans la liste en quelque sorte? Si c'est le cas, mieux vaut utiliser ConvertAll<T> ou Select<T>.

2

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

Vous pouvez ajouter un moyen de faire une carte, mais retourner une nouvelle liste, au lieu de travailler sur la liste adoptée en (et en retournant la liste peut se révéler utile à la chaîne d'autres opérations) ... peut-être une version surchargée avec un booléen qui indique si vous voulez retourner une nouvelle liste ou non, en tant que tel:

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