Dan*_*son 5 c# recursion ienumerable yield
我有以下方法效果很好,除了 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;
}
}
Run Code Online (Sandbox Code Playgroud)
因此,当我有以下节点并将“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
Run Code Online (Sandbox Code Playgroud)
......然后我得到了结果:
Top 2 aa
Top 2 ab
Top 2 ac
Run Code Online (Sandbox Code Playgroud)
这是正确的结果,但是,当我单步执行我的代码时,最外层循环继续处理前 3 名和前 4 名。如何跳出这个外循环?
如果我的代码正确,我想下面的代码可以解决您的问题
private static IEnumerable<Node> FindChildrenById(IEnumerable nodes, string parentText)
{
var result =
(from node in nodes
where (node.Parent == null && string.IsNullOrEmpty(parentText))
|| (node.Parent != null && node.Parent.Text == parentText)
select node).TakeWhile(node => !(node.Parent == null && string.IsNullOrEmpty(parentText)));
return result;
}
Run Code Online (Sandbox Code Playgroud)
它基于两种扩展方法(见下文)构建,并且应该只迭代直到满足您的目标找到条件
public static class IEnumerablExtensions
{
//Will iterate the graph in depth first order
public static IEnumerable<TResult> Select<TResult>(this IEnumerable collection, Func<Node, TResult> selector)
{
foreach (var obj in collection)
{
var node = obj as Node;
if (node != null)
{
yield return selector(node);
foreach (var n in node.Nodes.Select(selector))
{
yield return n;
}
}
}
}
public static IEnumerable<Node> Where(this IEnumerable collection, Predicate<Node> pred)
{
foreach (var node in collection.Select(x => x)) //iterate the list in graph first order
{
if (pred(node))
yield return node;
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:原始帖子中的 Select 方法存在错误(它没有迭代子项的子项),现已更正