In C# how do I memoize a function with two arguments?
Do I have to curry before memoization?
Wes Dyer wrote the Memoization code I typically use, but now I need two arguments
In C# how do I memoize a function with two arguments?
Do I have to curry before memoization?
Wes Dyer wrote the Memoization code I typically use, but now I need two arguments
You should be able to memoize a pair. The two arg function calls a single arg function that you memoize.
You just make an overloaded version of the Memoize method that has three generic types and takes a function with two parameters, and the two arguments. It still returns a parameterless function:
public static Func<R> Memoize<A1,A2,R>(this Func<A1,A2,R> f, A1 a1, A2 a2)
{
R value = default(R);
bool hasValue = false;
return () =>
{
if (!hasValue)
{
hasValue = true;
value = f(a1,a2);
}
return value;
};
}
Edit:
Alternatively, you need to make a custom IEqualityComparer for a KeyValuePair that contains the two arguments, for the Memoize method to be able to return a function with two parameters:
public static Func<A1,A2,R> Memoize<A1,A2,R>(this Func<A1,A2,R> f, IEqualityComparer<KeyValuePair<A1,A2>> comparer)
{
var map = new Dictionary<KeyValuePair<A1,A2>,R>(comparer);
return (a1,a2) =>
{
R value;
KeyValuePair<A1,A2> key = new KeyValuePair<A1,A2>(a1,a2);
if (map.TryGetValue(key, out value)) {
return value;
}
value = f(a1,a2);
map.Add(key, value);
return value;
};
}
Wes has another post where he gives a two (or more) argument version of Memoize. It does not require a custom comparer.
With new versions of .NET you can simplify the accepted solution's code a bit by using tuples
public static Func<TParam1, TParam2, TReturn> Memoize<TParam1, TParam2, TReturn>(Func<TParam1, TParam2, TReturn> func)
{
var map = new Dictionary<Tuple<TParam1, TParam2>, TReturn>();
return (param1, param2) =>
{
var key = Tuple.Create(param1, param2);
TReturn result;
if (!map.TryGetValue(key, out result))
{
result = func(param1, param2);
map.Add(key, result);
}
return result;
};
}