My code below finds all prime numbers below number
by creating a list of primes and checking to see if the next potential prime is evenly divisible by any primes in the list.
I'm trying to learn the ins and outs of yield return
. Right now I have a List<int> primes
that I use inside the function. But I'm returning the same data via yield return
. So my question is
Can I access the IEnumerable< int > from inside the function as I am creating it? So I can remove the List< int > primes altogether.
/// <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;
}
}
}
If you do not counting in your external code it is always better to return IEnumerable, because later you can change your implementation (without external code impact), for example, for yield iterator logic and conserve memory resources (very good language feature by the way).
You use a yield return statement to return each element one at a time. The sequence returned from an iterator method can be consumed by using a foreach statement or LINQ query. Each iteration of the foreach loop calls the iterator method.
IEnumerable in C# is an interface that defines one method, GetEnumerator which returns an IEnumerator interface. This allows readonly access to a collection then a collection that implements IEnumerable can be used with a for-each statement.
The yield return statement returns one element at a time. The return type of yield keyword is either IEnumerable or IEnumerator . The yield break statement is used to end the iteration. We can consume the iterator method that contains a yield return statement either by using foreach loop or LINQ query.
No, you cannot do that. The compiler builds a state machine to implement yield return
, and the calling code that enumerates through your enumerable is as much a part of its working as your code is. The compiler builds a hidden object that stores the current state of your code, including its call stack and locals, and it calls different pieces of your method as the caller invokes Current
and MoveNext
. Trying to enumerate your object from the beginning while another enumeration is in progress would mess up the ongoing enumeration, which would not be good.
In this particular case, you don't want it to happen either: the implementation of yield return
does not store the values that you produce, so if even if you could access your own IEnumerable
while enumerating, it would recursively call back itself multiple times to produce each new item, so it would take you ridiculously long time to produce even a moderate number of primes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With