Frage

Ich schreibe ein paar Erweiterungen, um die Karte nachzuahmen und Funktionen in Lisp zu reduzieren.

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

Die Transformationsfunktion reduziert Cruft wie folgt:

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

Macht das Sinn?Könnte es besser sein?

War es hilfreich?

Lösung

Diese sehen den Erweiterungen in Linq bereits sehr ähnlich:

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

Warum heißt das 2. Beispiel Transform?Beabsichtigen Sie, die Werte in der Liste irgendwie zu ändern?Wenn dies der Fall ist, ist es möglicherweise besser, es zu verwenden ConvertAll<T> oder Select<T>.

Andere Tipps

Laut diesem Link Funktionale Programmierung in C# 3.0:Wie Map/Reduce/Filter Ihre Welt rocken kann Folgendes ist das Äquivalent in C# unter dem System.Linq-Namespace:

Ich würde stattdessen die integrierten Func-Delegaten verwenden.Derselbe Code würde auf jedem IEnumerable funktionieren.Ihr Code würde wie folgt aussehen:

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

Möglicherweise möchten Sie eine Möglichkeit hinzufügen, eine Karte zu erstellen, aber eine neue Liste zurückzugeben, anstatt an der übergebenen Liste zu arbeiten (und die Rückgabe der Liste kann sich als nützlich erweisen, um andere Vorgänge zu verketten) ...vielleicht eine überladene Version mit einem booleschen Wert, der angibt, ob Sie eine neue Liste zurückgeben möchten oder nicht, also:

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

Ich würde empfehlen, Erweiterungsmethoden zu erstellen, die LinQ intern verwenden so was:

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

Hier einige Beispielverwendungen:

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

(Sehen https://github.com/cs-util-com/cscore#ienumerable-extensions für weitere Beispiele)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top