[英]Recursive IEnumerable doesn't work as expected?
我编写了一个递归函数,它产生了IEnumerable<int>
IEnumerable<int> Go(int b )
{
if (b==0) yield return 0;
else
foreach (var element in Go(b-1))
{
yield return element;
}
}
所以,如果我写
foreach (var element in Go(3))
{
Console.WriteLine (element);
}
它应该屈服
0
1
2
3
但它没有按预期工作。 (它显示0)。
在正常的递归函数(返回int - 没有Ienumerable)中,它工作正常。
题:
如何修复代码以使其产生预期值?
NB。 不,没有理由使用递归的Ienumerables。 在玩递归收益后,我才想到这一点。
因为你永远不会屈服于b本身而只会屈服于0。
IEnumerable<int> Go(int b)
{
if(b > 0) {
foreach (var element in Go(b-1))
yield return element;
}
yield return b;
}
请注意,如果您希望结果序列从0开始向上,则必须在foreach
之后 yield return b
。 让我们展开Go(3)
的第一个电话:
Go(3):
foreach(var element in Go(2)):
yield return element;
yield return 3;
所以3将是序列中的最后一项(因为所有其他项目之前都是yieled)。 我们现在展开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;
如您所见,结果相对于调用被“向后”链接:
Go(3) --> Go(2) --> Go(1) --> Go(0) --> 0 --> 1 --> 2 --> 3
我怀疑它会有什么不同 - 因为我看到的唯一具体yield
是yield 0
我想你想要这样的东西:
IEnumerable<int> Go(int b)
{
if (b > 0)
{
foreach (var element in Go(b-1))
{
yield return element;
}
}
yield return b;
}
但这仍然是非常低效的,并且将以更大的b
s吹嘘堆栈
对于你的问题:
你的代码:
会这样做:
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}
条件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
}
或没有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
}
}
为什么你的代码不起作用......让我们从最后开始......你想要[0,1,2,3]。 显然要获得该序列,必须有一个
yield return 0
yield return 1
yield return 2
yield return 3
但在您的代码中,您可以:
yield return 0
要么
yield return the Go function
无处你有一些代码可以返回非零值!
注意事实上正确的代码有一个
yield return b
其中b是传递给函数Go(int b)
,因此函数将首先递归调用自身以返回valeus 0 ... b-1然后产生b值。
假设您有一个名为enumerable的IEnumerable。 如果你写
foreach(var element in enumerable) yield return element;
和你写的完全一样
return enumerable;
如果你看结果和返回类型。 如果你试试
if(b == 0) yield return 0;
else return Go(b - 1);
它给出了编译器错误:“Iterator不能包含return语句”,因为如果你在其中编写一个带有yield return语句的函数,它将不会编译为函数而是迭代器,因此它不会真正“返回”。 让我们修改它以获得相同的行为,但为了清晰起见,使用“实际功能”。 要使其编译,您可以将其修改为
if (b == 0) return Enumerable.Repeat(0, 1); // or return Enumerable.Range(0, 1);
else return Go(b - 1);
但它并没有真正说清楚:你在那里所做的几乎就像:
return b == 0 ? 0 : Go(b-1);
但结果包含在IEnumerable中。 我希望现在很清楚为什么它只返回一个0。
根据b
参数添加可视化:(仅显示流量,如果产生)方法名称
我花了一段时间看看这里发生了什么。
你的代码有缺陷。 :-)
它的作用是Go方法只产生值0.如果用3调用,那么它会下降到最后一个递归调用,它返回0. foreach只迭代那个0并再次产生它。 因此,在每个级别上都会产生零作为唯一元素。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.