tags:

views:

720

answers:

4

Hi,

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 factorial for given n numbers (witout using recursive loops).

Below the code i tried. But this is not working.

public void FindFactorial(int range)
{

    var res = Enumerable.Range(1, range).Select(x => Enumerable.Range(0, x).Where(y => (y > 1)).Select(y => y * (y-1)));            
    foreach (var outt in res)
        Console.WriteLine(outt.ToString());

}

this is the procedure i used

  • loop through the numbers 1 to n -- Enumerable.Range(1, range).
  • select each number x and again loop them upto x times (instead of recursion)
  • and select the numbers Where(y => (y > 1)) greater than 1 and multiply that with (y-1)

i know i messed up somewhere. can someone tell me whats wrong and any other possible solution.

EDIT:

i am going to let this thread open for some time... since this is my initial steps towards lambda.. i found all the answers very useful and informative.. And its going to be fun and great learning seeing the differnt ways of approaching this problem.

Cheers

Ramesh Vel

+14  A: 

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.

Jon Skeet
10 out of 10 for style simply for the use of "x => x <= 1 ? 1 : x * factorial(x-1);"... x => x <= 1 :)
veggerby
thanks Jon, I have tried this way earlier. But i thought its cool doing this without recursion. thanks for the links.
Ramesh Vel
+1 for memoization... BTW, there's an interesting library called Elevate which provides an extension method for memoizing a function : http://elevate.codeplex.com/sourcecontrol/changeset/view/42940?projectName=elevate#690734
Thomas Levesque
@jon, thanks for pointing out the memoization...
Ramesh Vel
Man... I feel like an idiot. I had to go to Wikipedia and look up Memoization. I have a degree in Comp Sci, and I have never heard of this word before today. Thanks for teaching me something.
John Kraft
[Wiki Link](http://en.wikipedia.org/wiki/Memoization) for people like John and myself.
Scott Chamberlain
@Scott: Thanks, have edited it in.
Jon Skeet
+4  A: 

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

Thomas Levesque
@thomas, u rock... i never considered abt the Memoization.. thanks for giving an insight....
Ramesh Vel
Note that it is faster for large values, but probably slower for small values, because of the overhead of the dictionary insertion and lookup
Thomas Levesque
+1  A: 

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.

cfern
@cfern, thanks for the answer.. its cool .... you guys have given diffrent possibilities that i missed....
Ramesh Vel
+1  A: 

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
Gluip
@Gluip, thats a nice trick...
Ramesh Vel