I've written a recursive function which yields IEnumerable<int>
IEnumerable<int> Go(int b )
{
if (b==0) yield return 0;
else
foreach (var element in Go(b-1))
{
yield return element;
}
}
So If I write
foreach (var element in Go(3))
{
Console.WriteLine (element);
}
It should yield
0
1
2
3
But it doesn't work as expected. ( it displays 0).
In normal recursive function ( which return int - without Ienumerable) it works fine.
Question:
How can I fix the code so it yields the expected value ?
nb. No there's no reason for using recursive Ienumerables. It's just came to my mind after playing with recursive yields.
Because you never yield b itself but only yield 0.
IEnumerable<int> Go(int b)
{
if(b > 0) {
foreach (var element in Go(b-1))
yield return element;
}
yield return b;
}
Note that if you want the resulting sequence to start from 0 and go upwards you have to yield return b
after the foreach
. Let's unroll the first call for Go(3)
:
Go(3):
foreach(var element in Go(2)):
yield return element;
yield return 3;
So 3 will be the last item in the sequence (because all the others are yieled before it). Let's now unroll Go(2)
:
Go(3):
Go(2):
foreach(var element in Go(1)):
yield return element;
yield return 2;
yield return 3;
Go(1)
:
Go(3):
Go(2):
Go(1):
foreach(var element in Go(0))
yield return element;
yield return 1;
yield return 2;
yield return 3;
As you can see, result are chained "backwards" with respect to the calls:
Go(3) --> Go(2) --> Go(1) --> Go(0) --> 0 --> 1 --> 2 --> 3
I doubt that it would work anything different - because the only concrete yield
I see is yield 0
I guess you want something like this:
IEnumerable<int> Go(int b)
{
if (b > 0)
{
foreach (var element in Go(b-1))
{
yield return element;
}
}
yield return b;
}
but still this is highly inefficient and will blow the stack with bigger b
s
For your question:
Your code:
will do this:
b=3:
is b == 0? no ok, then enumerate and return everything from b=2...
b=2:
is b == 0? no ok, then enumerate and return everything from b=1...
b=1:
is b == 0? no ok, then enumerate everything from b=0...
b=0:
is b == 0? **YES** so yield a single **0**
everything was {0}
everything was {0}
everything was {0}
return is {0}
Yet another variant with condition b==0
static IEnumerable<int> Go(int b)
{
if (b == 0)
{
yield return 0; //return 0 if b==0;
yield break; // say that iteration end;
}
foreach (var el in Go(b - 1))
{
yield return el;
}
yield return b; //return current b as element of result collection
}
or without yield break
static IEnumerable<int> Go(int b)
{
if (b == 0)
{
yield return 0;
}
else
{
foreach (var el in Go(b - 1))
{
yield return el;
}
yield return b; //return current b as element of result collection
}
}
Why your code doesn't work... Let's start from the end... You want [0, 1, 2, 3]. Clearly to obtain that sequence, there must be a
yield return 0
yield return 1
yield return 2
yield return 3
But in your code you can:
yield return 0
or
yield return the Go function
nowhere you have some code that can yield return the non-zero value!
Note in fact that correct code has a
yield return b
where b is the value passed to the function Go(int b)
, so that the function will first call itself recursively to return the valeus 0...b-1 and then yield the b value.
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