Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you access the IEnumerable as you are yield returning it?

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;
        }
    }
}
like image 659
jb. Avatar asked Apr 21 '12 03:04

jb.


People also ask

Is it better to return IEnumerable or list?

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).

How does yield return work in C#?

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.

How do I return an IEnumerable object in C#?

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.

When using yield return in a method What should the methods return type be?

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.


1 Answers

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.

like image 191
Sergey Kalinichenko Avatar answered Oct 06 '22 08:10

Sergey Kalinichenko