2009-09-15 8 views
6

Ich begann gerade mit Lambdas und Linq Ausdruck für das Selbstlernen zu spielen. Ich nahm das einfache faktorielle Problem dafür. Mit dem kleinen komplexen Szenario finden Sie die Fakultät für gegebene n Zahlen (ohne rekursive Schleifen zu verwenden).Faktor von n Zahlen mit C# Lambda ..?

Unter dem Code habe ich versucht. Aber das funktioniert nicht.

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

} 

Dies ist die Prozedur i

verwendet
  • Schleife durch die Zahlen 1 bis n - Enumerable.Range (1, Bereich).
  • jede Zahl x auszuwählen und wieder Schleife sie bis zu x-mal (statt Rekursion)
  • und wählen die Zahlen Wo (y => (y> 1)) größer als 1 ist und sich vermehren, dass mit (y-1)

ich weiß, ich irgendwo vermasselt. kann mir jemand sagen, was falsch ist und jede andere mögliche Lösung.

EDIT:

Ich werde diesen Thread einige Zeit offen lassen ... da dies meine ersten Schritte in Richtung Lambda ist .. ich alle Antworten sehr nützlich und informativ .. Und sein Gehen Spaß zu haben und großartig zu lernen, die verschiedenen Wege zu sehen, dieses Problem anzugehen.

Antwort

21

Derzeit gibt es keine Rekursion - das ist das Problem. Sie nehmen nur eine Folge von Zahlen und projizieren jede Zahl auf "sich selbst".

Der einfache und ineffizienter Weg, um eine faktorielle Funktion des Schreibens ist:

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

Regel dann Sie in memoization erhalten zu vermeiden, dass immer wieder die gleiche Sache zu berechnen. Vielleicht möchten Sie Wes Dyer's blog post auf diese Art von Sache lesen.

+3

10 von 10 Punkten für Stil einfach für die Verwendung von "x => x <= 1 1: x * factorial (x-1);" .. . x => x <= 1 :) – veggerby

+0

danke Jon, ich habe diesen Weg schon früher ausprobiert. Aber ich dachte, es wäre cool, dies ohne Rekursion zu tun. Danke für die Links. – RameshVel

+1

+1 für Memoization ... Übrigens gibt es eine interessante Bibliothek namens Elevate, die eine Erweiterungsmethode zum Memoisieren einer Funktion bietet: http://elevate.codeplex.com/sourcecontrol/changeset/view/42940?projectName=elevate#690734 –

6

einfach auf Jons Antwort weiter hier ist, wie Sie die Fakultätsfunktion memoize können, so dass Sie alles, was nicht bei jedem Schritt neu berechnen:

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: eigentlich der obige Code nicht korrekt ist, weil factorial Anrufe factorial, nicht factorialMemoized. Hier ist eine bessere 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()); 

Mit diesem Code wird factorial 10-mal aufgerufen, gegen 55 mal für die vorherige Version

+0

@thomas, du rockst ... ich habe nie über die Memoization nachgedacht .. danke für einen Einblick .... – RameshVel

+0

Beachten Sie, dass es für große Werte schneller ist, aber wahrscheinlich langsamer für kleine Werte, wegen der Overhead der Wörterbucheinfügung und Suche –

3

Ich habe versucht, mit so etwas wie F # 's-Scan-Funktion zu kommen, scheiterte aber, da meinen LINQ ist noch nicht sehr stark.

Hier ist meine Ungeheuerlichkeit:

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

Wenn jemand weiß, ob es tatsächlich ein Äquivalent von F # 's-Scan-Funktion in LINQ ist, die ich verpasst, wäre ich sehr interessiert.

+0

@cfern, danke für die Antwort .. es ist cool .... Sie haben verschiedene Möglichkeiten gegeben, die ich verpasste .... – RameshVel

7

Einfache obwohl keine Rekursion hier:

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

3.Factorial() == 6 
+0

das ist ein netter Trick .. . – RameshVel