I just started playing with lambdas and Linq expression for self learning. I took the simple factorial problem for this. with the little complex scenario where find the fact
Just to continue on Jon's answer, here's how you can memoize the factorial function so that you don't recompute everything at each step :
public Func<T, TResult> Memoize<T, TResult>(Func<T, TResult> func)
{
Dictionary<T, TResult> _resultsCache = new Dictionary<T, TResult>();
return (arg) =>
{
TResult result;
if (!_resultsCache.TryGetValue(arg, out result))
{
result = func(arg);
_resultsCache.Add(arg, result);
}
return result;
};
}
...
Func<int, int> factorial = null; // Just so we can refer to it
factorial = x => x <= 1 ? 1 : x * factorial(x-1);
var factorialMemoized = Memoize(factorial);
var res = Enumerable.Range(1, 10).Select(x => factorialMemoized(x));
foreach (var outt in res)
Console.WriteLine(outt.ToString());
EDIT: actually the code above is not correct, because factorial
calls factorial
, not factorialMemoized
. Here's a better version :
Func<int, int> factorial = null; // Just so we can refer to it
Func<int, int> factorialMemoized = null;
factorial = x => x <= 1 ? 1 : x * factorialMemoized(x-1);
factorialMemoized = Memoize(factorial);
var res = Enumerable.Range(1, 10).Select(x => factorialMemoized(x));
foreach (var outt in res)
Console.WriteLine(outt.ToString());
With that code, factorial
is called 10 times, against 55 times for the previous version
I tried to come up with something resembling F#'s scan function, but failed since my LINQ isn't very strong yet.
Here's my monstrosity:
//this is similar to the folowing F# code:
//let result = [1..10] |> List.scan (fun acc n -> acc*n) 1
var result =
Enumerable.Range(1, 10)
.Aggregate(new List<int>(new[] { 1 }),
(acc, i) => {
acc.Add(i * acc.Last());
return acc;
}
);
foreach(var num in result) Console.WriteLine("{0}",num);
If anyone knows if there actually is an equivalent of F#'s scan function in LINQ that I missed, I'd be very interested.
Simple although no recursion here:
public static int Factorial(this int count)
{
return count == 0
? 1
: Enumerable.Range(1, count).Aggregate((i, j) => i*j);
}
3.Factorial() == 6
Currently there's no recursion - that's the problem. You're just taking a sequence of numbers, and projecting each number to "itself * itself-1".
The simple and inefficient way of writing a factorial function is:
Func<int, int> factorial = null; // Just so we can refer to it
factorial = x => x <= 1 ? 1 : x * factorial(x-1);
for (int i = 1; i <= range; i++)
{
Console.WriteLine(factorial(i));
}
Typically you then get into memoization to avoid having to repeatedly calculate the same thing. You might like to read Wes Dyer's blog post on this sort of thing.