2012-04-21 34 views
6

我的代碼如下,通過創建素數列表並檢查下列潛在素數是否可以被列表中的任何素數均勻整除,從而找到所有素數在number以下的素數。您是否可以訪問IEnumerable,因爲您正在返回它?

我在努力學習yield return的來龍去脈。現在我有一個List<int> primes,我在函數內使用。但我通過yield return返回相同的數據。所以我的問題是

我可以從函數內部訪問IEnumerable < int>,因爲我正在創建它?所以我可以刪除列表< int>素數。

/// <summary> 
/// Finds all primes below <paramref name="number"/> 
/// </summary> 
/// <param name="number">The number to stop at</param> 
/// <returns>All primes below <paramref name="number"/></returns> 
private static IEnumerable<long> PrimeNumbers(long number) 
{ 
    yield return 2; 
    List<long> primes = new List<long>(2);   

    for(long num = 3; num < number; num += 2) 
    { 

     //if any prime lower then num divides evenly into num, it isn't a prime 
     //what I'm doing now 
     if(!primes.TakeWhile(x => x < num).Any(x => num % x == 0)) 
     { 
      primes.Add(num); 
      yield return num; 
     } 

     //made-up syntax for what I'd like to do 
     if(!this.IEnumerable<long> 
       .TakeWhile(x => x < num).Any(x => num % x == 0)) 
     { 
      yield return num; 
     } 
    } 
} 
+0

簡答題:不會。長答案:有更好的方法可以讓素數達到某個數。檢查Sundaram的篩網:http://en.wikipedia.org/wiki/Sieve_of_Sundaram – SimpleVar 2012-04-21 03:44:51

+0

您也可以通過參考Eratosthenes篩選來改進:http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes,甚至更多Atkin的篩選器:http://en.wikipedia.org/wiki/Sieve_of_Atkin我認爲這是目前已知的用於生成素數(如果不是最快的)的最快方法之一,並且wiki中還有僞代碼來幫助您獲得開始。 – SimpleVar 2012-04-21 03:47:51

+0

@YoryeNathan我在維基百科上看到了這些篩子,如果我將這些代碼保留在任何重要的地方,我可能會使用它們。這段代碼更有助於培養自己如何思考「收益回報」的思維方式。 – 2012-04-21 03:49:58

回答

4

不,你不能這樣做。編譯器建立一個狀態機來實現yield return,通過你的枚舉枚舉的調用代碼與你的代碼一樣是工作的一部分。編譯器構建一個隱藏對象,該對象存儲代碼的當前狀態,包括其調用堆棧和本地代碼,並調用不同的方法,因爲調用者調用CurrentMoveNext。試圖枚舉你的對象從一開始,而另一個枚舉正在進行會攪亂正在進行的枚舉,這將不好。

在這種特殊情況下,您不希望它發生:yield return的實施不存儲您生成的值,因此如果即使您在枚舉時可以訪問自己的IEnumerable,它也會遞歸地回調本身多次產生每個新物品,所以如果要產生中等數量的素數,你需要花費很長的時間。

+0

當然可以。遞歸或嵌套枚舉應該被自動處理,這是它們之美的一部分。這將做到這一點:'如果(!PrimeNumbers(num).Any(x => num%x == 0))yield return num'。只是在LINQPad中測試過。然而,你的第二點是,它是非常低效的。你可以通過簡單地在函數內部做一個'Console.WriteLine(..)'來看看它枚舉了多少次相同的結果。 – mellamokb 2012-04-21 03:38:08

+1

@mellamokb這不是從創建序列的函數中訪問*本身*。它使用自己的狀態,狀態機和其他所有內容訪問自己的相同副本*。這就是爲什麼它不會中斷,這就是爲什麼它很慢:) – dasblinkenlight 2012-04-21 03:41:37

+0

啊!我現在在同一頁面上:)是的,您不能從同一個實例中獲取先前的條目,因爲之前的狀態不再存在。 – mellamokb 2012-04-21 03:42:33

2

整體枚舉器不是像List<int> primes這樣的容器。這是一個尋找素數的「過程」。如果你遞歸地使用你自己的過程來生成素數列表來反對尋找下一個素數,那麼你將會遞歸地枚舉相同的結果,這將會非常低效。考慮會發生什麼(如果你能真正做到這一點),用於查找素數最多爲10

yield return 2 
num = 3 
IEnumerable<long>.TakeWhile(x => x < 3).Any(x => num % x == 0) 
    new enumerator 
    yield return 2 
yield return 3 
num = 4 
IEnumerable<long>.TakeWhile(x => x < 4).Any(x => num % x == 0) 
    new enumerator 
    yield return 2 
    num = 3 
    IEnumerable<long>.TakeWhile(x => x < 3).Any(x => num % x == 0) 
     new enumerator 
     yield return 2 
    yield return 3 
num = 5 
IEnumerable<long>.TakeWhile(x => x < 5).Any(x => num % x == 0) 
    new enumerator 
    yield return 2 
    num = 3 
    IEnumerable<long>.TakeWhile(x => x < 4).Any(x => num % x == 0) 
     new enumerator 
     yield return 2 
     num = 3 
     IEnumerable<long>.TakeWhile(x => x < 3).Any(x => num % x == 0) 
      new enumerator 
      yield return 2 
     yield return 3 
     num = 4 
etc. 

這是一個指數級增長enumartion。這類似於通過計算f(n-1) + f(n-2)天真地找到斐波納契數字。你一遍又一遍地做很多相同的工作,甚至更高的數字。內部的素數列表充當一種緩存,使您的枚舉非常高效。

相關問題