2009-09-15 15 views
6

私はちょうどlambdaとLinq式で自己学習を始めました。私はこれに対して単純な階乗問題を取りました。少し複雑なシナリオでは、与えられたn個の数値の階乗を見つけることができます(再帰的ループを使用してwitout)。私が試したコードの下nの階乗はC#λを使用しています..?

。しかし、これは動作していません。 Enumerable.Range(1、レンジ) -

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

これは、iがNに番号1を介して

  • ループを使用する手順です。
  • 各数xを選択し、再度X回(代わりに 再帰)
  • の点で最大ループそれらをと数字を選択する場合(Y =>(Y> 1)) 1より大きく、乗算その と(y-1)

私はどこかでうんざりしています。誰かが私に何が間違っているか、他の可能な解決策を教えてくれる?

はEDIT:

私はしばらくの間、このスレッドがオープンできるようにするつもりです...これは、ラムダに向けた私の最初のステップであるので、..私は..すべての答えは非常に便利で有益発見し、その行きますこの問題に近づく別の方法を見て楽しいと偉大な学習であること。

答えて

21

は現在のところ再帰はありません - それが問題です。あなたは、一連の数字を取って、各数字を「それ自身」1に投影しているだけです。通常

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

あなたはその後、何度も同じことを計算することを避けるためにmemoizationに入る:

階乗関数を書くのシンプルかつ非効率的な方法です。あなたはこの種のことについてWes Dyer's blog postを読むのが好きかもしれません。ただ、Jonの答えに継続する

+3

10単に使用するためのスタイルのための10のうちの "x => X <= 1?1:X *階乗(X-1);" .. 。x => x <= 1 :) – veggerby

+0

ジョンさん、ありがとうございました。しかし、私は再帰なしでこれをやってクールだと思った。リンクをありがとう。 – RameshVel

+1

+1のメモ... BTW、関数をメモするための拡張メソッドを提供する興味深いライブラリElevateがあります:http://elevate.codeplex.com/sourcecontrol/changeset/view/42940?projectName=elevate#690734 –

6

は、ここにあなたが各ステップですべてのものを再計算しないように、あなたは階乗関数をmemoizeすることができます方法は次のとおりです。

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:理由factorial実際に上記のコードは、正しくありません。 factorialMemoizedではなく、factorialが呼び出されます。

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

そのコードでは、factorial私はF#のスキャン機能に似た何かを思い付くしようとした以前のバージョン

+0

@thomasは、uは岩...私は決してメモ化アプトと考え...それは速く、大きな値のためであることを.... – RameshVel

+0

注意洞察力を与えるためのおかげで、おそらく遅くします。小さな値のため、理由辞書挿入と検索 –

3

のために55回に対して、10回呼び出されますが、私のLINQので、失敗しました。ここでは、より良いバージョンですまだあまり強くない。ここで

は私の奇形です:

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

実際に私が逃したLINQでF#のスキャン機能の同等がある場合、誰もが知っている場合、私は非常に興味があると思います。

+0

@cfernのオーバーヘッドの、答えのためのおかげで...そのクールな....君たちは私が逃した切り抜いた可能性を与えている.... – RameshVel

7

単純ですが、ここで再帰なし:

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

3.Factorial() == 6 
+0

は素敵なトリックをthatsの.. 。 – RameshVel

関連する問題