6

number以下の私のコードは、素数のリストを作成し、次の潜在的な素数がリスト内の任意の素数で割り切れるかどうかを確認することにより、以下のすべての素数を見つけます。

の内外を学ぼうとしていますyield return。現在List<int> primes、関数内で使用する があります。しかし、私はを介して同じデータを返していますyield return。だから私の質問は

関数を作成しているときに、関数内から IEnumerable< int > にアクセスできますか? したがって、 List< 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;
        }
    }
}
4

2 に答える 2

4

いいえ、それはできません。コンパイラは を実装するステート マシンを構築し、yield return列挙型を介して列挙する呼び出しコードは、コードと同じように動作の一部です。コンパイラは、コードの現在の状態 (コール スタックとローカルを含む) を格納する隠しオブジェクトを作成し、呼び出し元が と を呼び出すCurrentと、メソッドのさまざまな部分を呼び出しますMoveNext。別の列挙の進行中にオブジェクトを最初から列挙しようとすると、進行中の列挙が台無しになり、良くありません。

この特定のケースでは、それが発生することも望ましくありません: の実装は、生成した値を保存しないため、列挙中にyield return自分自身にアクセスできたとしても、再帰的に複数回コールバックして、それぞれを生成しますIEnumerable新しいアイテムなので、適度な数の素数を生成するのに途方もなく長い時間がかかります.

于 2012-04-21T03:27:30.620 に答える
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.

それは指数関数的に増加する列挙です。これは単純に を計算してフィボナッチ数を見つけることに似ていますf(n-1) + f(n-2)。同じ作業を何度も何度も行っており、数値が高くなるにつれてさらに多くの作業を行っています。素数の内部リストは、列挙を非常に効率的にする一種のキャッシュとして機能します。

于 2012-04-21T03:27:45.047 に答える