Domanda

Sto scrivendo alcune estensioni per imitare la mappa e ridurre le funzioni 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);
}

La funzione di trasformazione ridurrà i cruft come:

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

Ha senso ciò?Potrebbe essere migliore?

È stato utile?

Soluzione

Sembrano già molto simili alle estensioni di 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 */);

Perché il secondo esempio si chiama Transform?Intendi modificare in qualche modo i valori nell'elenco?Se è così potrebbe essere meglio usarlo ConvertAll<T> O Select<T>.

Altri suggerimenti

Secondo questo collegamento Programmazione funzionale in C# 3.0:In che modo Mappa/Riduci/Filtro possono sconvolgere il tuo mondo i seguenti sono gli equivalenti in C# nello spazio dei nomi System.Linq:

Utilizzerei invece i delegati Func integrati.Questo stesso codice funzionerebbe su qualsiasi IEnumerable.Il tuo codice si trasformerebbe in:

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

Potresti voler aggiungere un modo per creare una mappa ma restituire un nuovo elenco, invece di lavorare sull'elenco passato (e restituire l'elenco può rivelarsi utile per concatenare altre operazioni)...forse una versione sovraccaricata con un valore booleano che indica se vuoi restituire un nuovo elenco o meno, in quanto tale:

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

Consiglierei di creare metodi di estensione che utilizzino internamente LinQ come questo:

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

Ecco alcuni esempi di utilizzo:

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

(Vedere https://github.com/cs-util-com/cscore#ienumerable-extensions per ulteriori esempi)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top