2009-09-15 11 views
6

Acabo de empezar a jugar con lambdas y expresión de Linq para autoaprendizaje. Tomé el problema factorial simple para esto. con el pequeño escenario complejo donde se encuentra el factorial para n números dados (sin usar bucles recursivos).factorial de n números usando C# lambda ...?

Debajo del código probé. Pero esto no está funcionando.

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

} 

Este es el procedimiento i utilizado

  • bucle a través de los números 1 a n - Enumerable.Range (1, rango).
  • seleccionar cada número x y de nuevo bucle de ellos hasta x veces (en lugar de recursión)
  • y seleccionar los números Dónde (y => (y> 1)) mayor que 1 y que se multiplican con (y-1)

Sé que cometí un error en alguna parte. alguien puede decirme qué está mal y cualquier otra solución posible.

EDIT:

voy a dejar que este hilo abierto por algún tiempo ... ya que este es mis pasos iniciales hacia lambda .. he encontrado todas las respuestas muy útil e informativo .. Y su ir ser divertido y excelente para aprender a ver las diferentes maneras de abordar este problema.

Respuesta

21

Actualmente no hay recursión: ese es el problema. Solo está tomando una secuencia de números y proyectando cada número a "sí mismo" -1 ".

La manera más simple y eficiente de escribir una función factorial es:

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

Normalmente, a continuación, entrar en memoization para evitar tener que calcular repetidamente la misma cosa. Le gustaría leer Wes Dyer's blog post en este tipo de cosas.

+3

10 de los 10 por el estilo, simplemente por el uso de "x => x <= 1 1:? X * factorial (x-1);" .. . x => x <= 1 :) – veggerby

+0

gracias Jon, lo he intentado de esta manera antes. Pero pensé que es genial hacer esto sin recurrencia. gracias por los enlaces. – RameshVel

+1

+1 para la memorización ... Por cierto, hay una interesante biblioteca llamada Elevate que proporciona un método de extensión para memorizar una función: http://elevate.codeplex.com/sourcecontrol/changeset/view/42940?projectName=elevate#690734 –

6

Sólo para continuar en la respuesta de Jon, aquí es cómo se puede memoize la función factorial de modo que no recalcular todo a cada paso:

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: en realidad el código anterior no es correcto, porque factorial llama al factorial, no al factorialMemoized. Aquí hay una versión mejor:

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

Con ese código, factorial se llama 10 veces, contra 55 veces para la versión anterior

+0

@thomas, u rock ... nunca consideré abt the Memoization ... gracias por darnos una idea ... – RameshVel

+0

Tenga en cuenta que es más rápido para valores grandes, pero probablemente más lento para valores pequeños, debido a la sobrecarga de la inserción del diccionario y la búsqueda –

3

Traté de llegar a algo parecido a la función de escaneo F # 's, pero no pudo ya que mi LINQ no es muy fuerte todavía

Aquí es mi monstruosidad:

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

Si alguien sabe si realmente existe un equivalente de la función de escaneo F # 's en LINQ que echaba de menos, yo estaría muy interesado.

+0

@cfern, gracias por la respuesta ... es genial .... ustedes han dado diferentes posibilidades que me perdí .... – RameshVel

7

simple aunque sin recursividad aquí:

public static int Factorial(this int count) 
{ 
     return count == 0 
        ? 1 
        : Enumerable.Range(1, count).Aggregate((i, j) => i*j); 
} 

3.Factorial() == 6 
+0

que es un truco agradable .. . – RameshVel