2009-09-15 6 views
6

Je viens de commencer à jouer avec lambdas et l'expression Linq pour l'auto-apprentissage. J'ai pris le problème factoriel simple pour cela. avec le petit scénario complexe où trouver la factorielle pour n nombres donnés (sans utiliser de boucles récursives).factorielle de n nombres en utilisant C# lambda ..?

Ci-dessous le code que j'ai essayé. Mais ça ne fonctionne pas.

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

} 

cette procédure est le i utilisé

    boucle
  • à travers les numéros 1 à n - Enumerable.Range (1, rang).
  • sélectionner chaque nombre x et leur boucle à nouveau jusqu'à x fois (au lieu de de récursion)
  • et sélectionner les numéros Où (y => (y> 1)) supérieur à 1 et multiplier ce avec (y-1)

Je sais que j'ai foiré quelque part. Quelqu'un peut-il me dire ce qui est mal et toute autre solution possible.

EDIT:

je vais laisser ce fil ouvert pendant un certain temps ... car ce sont mes premiers pas vers lambda .. je l'ai trouvé toutes les réponses très utile et instructif .. Et sa va être amusant et apprendre en voyant les différentes façons d'aborder ce problème.

Répondre

21

Actuellement, il n'y a pas de récursivité - c'est le problème. Vous prenez juste une suite de nombres et vous projetez chaque nombre sur "lui-même * lui-même".

La façon simple et inefficace d'écrire une fonction factoriel est:

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

En général, vous obtenez alors en memoization pour éviter d'avoir à calculer à plusieurs reprises la même chose. Vous pourriez aimer lire Wes Dyer's blog post sur ce genre de chose.

+3

10 sur 10 pour le style simple pour l'utilisation de "x => x <= 1 1: x * factoriel (x-1);" .. x => x <= 1 :) – veggerby

+0

merci Jon, j'ai essayé de cette façon plus tôt. Mais j'ai pensé que c'était cool de le faire sans récursion. merci pour les liens. – RameshVel

+1

+1 pour mémoization ... BTW, il y a une bibliothèque intéressante appelée Elevate qui fournit une méthode d'extension pour mémoriser une fonction: http://elevate.codeplex.com/sourcecontrol/changeset/view/42940?projectName=elevate#690734 –

6

Pour poursuivre sur la réponse de Jon, voici comment vous pouvez memoize la fonction factoriel afin que vous ne recalculez pas tout à chaque étape:

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 fait le code ci-dessus n'est pas correct, parce que factorial appelle factorial, et non factorialMemoized. Voici une meilleure 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()); 

Avec ce code, factorial est appelé 10 fois, contre 55 fois pour la version précédente

+0

@thomas, u rock ... je n'ai jamais considéré abt la Memoization .. merci de donner un aperçu .... – RameshVel

+0

Notez qu'il est plus rapide pour les grandes valeurs, mais probablement plus lent pour les petites valeurs, en raison de l'overhead de l'insertion du dictionnaire et la recherche –

3

J'ai essayé de trouver quelque chose qui ressemble à la fonction de balayage de F #, mais a échoué depuis mon LINQ n'est pas encore très fort.

Voici mon monstruosité:

//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 quelqu'un sait s'il est en fait un équivalent de la fonction de balayage de F # dans LINQ que j'ai manqué, je serais très intéressé.

+0

@cfern, merci pour la réponse .. son cool .... vous avez donné différentes possibilités que j'ai raté .... – RameshVel

7

simple bien que pas récursion ici:

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

3.Factorial() == 6 
+0

c'est un bon tour .. . – RameshVel

Questions connexes