如何摆脱递归 IEnumerable使用yieldbreak循环?
我有以下效果很好的方法,除了yield break 语句仅突破当前枚举器之外。我明白为什么会出现这种情况,但我对如何通过递归堆栈传播产量分解一无所知。
private static IEnumerable<Node> FindChildrenById(IEnumerable nodes, string parentText) {
var en = nodes.GetEnumerator();
var targetFound = false;
while (en.MoveNext()) {
var node = en.Current as Node;
if (node != null)
{
if (node.Parent == null && string.IsNullOrEmpty(parentText))
{
//Returns the top level nodes if an empty parentIdis entered
targetFound = true;
yield return node;
}
else if (node.Parent != null && node.Parent.Text == parentText)
{
//returns the nodes belonging to the parent
yield return node;
}
else
{
//Recurse into the children to see whether one of these is the node to find
foreach (var nd in FindChildrenById(node.Nodes, parentText))
{
yield return nd;
}
}
}
}
if (targetFound)
{
yield break;
}
}
因此,当我有以下节点并传递“Top 2 a”作为parentText...
Top 1
Top 1 a
Top 1 b
Top 2
Top 2 a
Top 2 aa
Top 2 ab
Top 2 ac
Top 2 b
Top 3
Top 3 a
Top 3 b
Top 4
...然后我得到结果:
Top 2 aa
Top 2 ab
Top 2 ac
这是正确的结果,但是,当我单步执行代码时,最外层循环继续处理 Top 3 和 Top 4。如何跳出这个外循环?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果我的代码正确,我想下面的代码将解决您的问题
它是基于两个扩展方法构建的(见下文),并且应该只迭代直到满足您的目标找到标准
编辑:有一个错误在原始发布的 Select 方法中(它没有迭代子项的子项),现在已更正
If I got your code right, I guess the code below will solve your problem
It's built on two extension methods (see below) and should only iterate until your target found criteria is met
EDIT: There was an error in the Select method in the original posting (it didn't iterate the children of children) that is now corrected
我假设该函数实际上名为 FindChildrenById,否则我看不到任何递归发生。
在这种假设下,您可以使用异常(我强烈建议不要这样做),或者返回一个
KeyValuePair>
其中bool
部分将是用于表示链上的早期退出。然后,在 API 级别上,公开一个包装器方法,该方法仅返回
IEnumerable
部分并抛出bool
部分。这是一个示例,给定类
Node
:您可以像这样遍历和快捷方式:
I'm assuming that the function is actually named
FindChildrenById
, otherwise I can't see any recursion going on.Under this assumption you can either use exceptions (which I would strongly recommend against), or return a
KeyValuePair<bool, IEnumerable<Node>>
where thebool
part will be used to signal an early out up the chain.Then, on the API level, expose a wrapper method that simply returns the
IEnumerable<Node>
part and throws way thebool
part.Here's an example, given the class
Node
:You can traverse and shortcut like this:
这对你有用吗?
更新:
我已经考虑了更多。这对于递归来说可能很棘手。您将需要保留一些状态变量来打破所有循环。
如果 C# 有尾递归,我建议将代码转换为 CPS。
你总是可以用 MSIL 编写它:)
Will that work for you?
Update:
I have given it some more thought. This might be tricky with recursion. You will need to keep some state variable to break out of all the loops.
If C# had tail-recursion, I would suggest converting the code to CPS.
You could always write it in MSIL :)