Can you access IEnumerable as you return it?

My code below finds all primes below number , creating a list of primes and checking if the next potential number will simply be divisible by any primes in the list.

I am trying to find out all the inputs and outputs of a yield return . Right now I have a List<int> primes that I use inside the function. But I am returning the same data through yield return . So my question is:

Can I access an IEnumerable <int> inside a function, how do I create it? Therefore, I can remove the List <int> of primes.

 /// <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; } } } 
+6
source share
2 answers

No, you cannot do this. The compiler creates a state machine to implement yield return , and the call code that is enumerated through your enumerated one is as much a part of its work as your code. The compiler creates a hidden object that stores the current state of your code, including its call stack and locals, and it calls different parts of your method, because the caller calls Current and MoveNext . Trying to list your object from the very beginning, while another enumeration is being performed, the current enumeration will be corrupted, which will not be good.

In this particular case, you also donโ€™t want this to happen: the yield return implementation does not save the values โ€‹โ€‹you create, so even if you could access your own IEnumerable on an enumeration, it will recursively call itself back several times to create each a new element, so it would take a ridiculously long time to produce even a moderate amount of primes.

+4
source

A generic enumerator is not a container of type List<int> primes . This is a โ€œprocessโ€ for finding prime numbers. If you recursively use your own process to generate a list of primes to work against finding the next prime number, you will recursively list the same results over and over again, which will be extremely inefficient. Think about what will happen (if you really do) to find primes up to 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. 

This is an exponentially increasing enumeration. This is similar to the naive detection of Fibonacci numbers by calculating f(n-1) + f(n-2) . You do a lot of the same work over and over, and especially since you achieve higher numbers. An internal list of primes serves as a kind of cache to make your listing very efficient.

+2
source

Source: https://habr.com/ru/post/913763/


All Articles