2009-09-15 14 views
6

Właśnie zacząłem grać z wyrażeniem lambdas i Linq dla samokształcenia. Zrobiłem to za pomocą prostego problemu z czynnikiem. z małym skomplikowanym scenariuszem, w którym znajduje się silnia dla podanych liczb n (bez użycia pętli rekursywnych).silnia n liczb przy użyciu C# lambda ..?

Poniżej kodu próbowałem. Ale to nie działa.

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

} 

to Procedura stosowane

  • Przelotowe liczb 1 do N - Enumerable.Range (1, zakres).
  • wybrać każdą liczbę X i ponownie pętli JE zapisu do czasu x (zamiast rekurencji)
  • i wybierać numery przypadku (r => (r> 1)) większy niż 1 i pomnożyć z (y-1)

Wiem, że gdzieś zawiedli. czy ktoś może mi powiedzieć, co jest nie tak i jakie jest inne możliwe rozwiązanie.

EDIT:

mam zamiar dać ten wątek otwarty przez jakiś czas ... ponieważ jest to moje pierwsze kroki w kierunku lambda .. znalazłem wszystkie odpowiedzi bardzo przydatne i pouczające .. I jego dzieje być zabawą i wspaniałą nauką, widząc różne sposoby podejścia do tego problemu.

Odpowiedz

21

Obecnie nie ma rekursji - to jest problem. Po prostu robisz sekwencję liczb i rzutujesz każdy numer na "sam * sam-1".

Prosta i nieefektywny sposób pisania czynnikowy funkcji jest następująca:

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

Zazwyczaj można następnie dostać się memoization aby uniknąć konieczności ciągłego obliczania samo. Możesz przeczytać Wes Dyer's blog post na ten temat.

+3

10 z 10 dla stylu po prostu za korzystanie z "x => X <= 1 1: x * silnia (x-1);" .. x => x <= 1 :) – veggerby

+0

dzięki Jon, próbowałem w ten sposób wcześniej. Ale myślałem, że to fajne, robiąc to bez rekursji. dzięki za linki. – RameshVel

+1

+1 do zapamiętania ... BTW, istnieje interesująca biblioteka o nazwie Elevate, która zapewnia metodę rozszerzającą do zapamiętania funkcji: http://elevate.codeplex.com/sourcecontrol/changeset/view/42940?projectName=elevate#690734 –

6

Wystarczy wejść na odpowiedź Jona, oto jak można memoize funkcję silni tak, aby nie przeliczyć wszystko na każdym kroku:

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: faktycznie powyższy kod nie jest prawidłowy, ponieważ factorial nazywa się factorial, a nie factorialMemoized. Oto lepsza wersja:

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

Z tym kodem, factorial nazywa się 10 razy, przed 55 razy do poprzedniej wersji

+0

@thomas, u rock ... nigdy nie brałem pod uwagę Memoization .. dzięki za udzielenie wglądu ... – RameshVel

+0

Zauważ, że jest szybszy dla dużych wartości, ale prawdopodobnie wolniejszy dla małych wartości, ze względu na narzut słownikowego wstawiania i wyszukiwania –

3

starałem się wymyślić coś przypominającego funkcję skanowania F # 's, ale nie powiodło się, ponieważ moim LINQ nie jest jeszcze bardzo silny.

Oto mój potworność:

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

Jeśli ktoś wie, czy tam rzeczywiście jest odpowiednikiem funkcji skanowania F # 's w LINQ, że brakowało, byłbym bardzo zainteresowany.

+0

@ cfern, dziękuję za odpowiedź .. jej fajnie .... daliście różne możliwości, które przegapiłem ... – RameshVel

7

Proste chociaż nie rekurencji tutaj:

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

3.Factorial() == 6 
+0

to fajna sztuczka .. . – RameshVel