Traversing all descendants of an object
我在遍历对象的所有后代时遇到问题。
下面代码中的
我能成功地对孩子们进行手术。然后我检查这些孩子是否有孩子,如果有,我也可以对他们进行手术。
然而,我需要检查所有的后代,以防有更多的深度,而不仅仅是孙子。除了下面的代码外,我还尝试了while循环,但它变得非常混乱,所以我把它忽略了。
这是我恢复到的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | foreach (var child in unit.ChildUnits) { //do something here with the child (I know it sounds dodgy). bool hasMoreChildren = child.ChildUnits.Count != 0; if(hasMoreChildren) { foreach (var descendant in child.ChildUnits) { //do something here with the descendant. } } } |
我可以再深入一个层次,因为对于一个单位来说,深度比这个要小的多。但这不是一个干净的解决方案。
我想我可能需要使用一个图遍历算法和/或递归,但我想得到一些关于如何最有效地解决这个问题的建议。
编辑:是否可以在不定义新函数/方法的情况下执行此操作?
Edit: Is it possible to do this without defining a new function/method?
号
你可以使用一个匿名的方法……我知道这并不是"不定义一个新方法"。
但是,还有一个问题你应该注意:循环引用…即使你不认为会有
这是一个实现,没有定义任何新方法
1 2 3 4 5 6 7 8 9 10 11 12 | Action<IEnumerable<Unit>> process = null; var processed = new HashSet<Unit>(); process = list => { foreach(var u in list.Where (processed.Add)) { // do something here with u //... and then process children process(u.ChildUnits); } }; process(myList); // do the actual processing |
您可以使用递归:
1 2 3 4 5 6 7 8 | void processChildren(List<Unit> children) { foreach (var child in children) { //do something here with the child (I know it sounds dodgy). processChildren(child.Children); // recursive call here } } |
如果不想定义新方法,也可以滚动自己的堆栈:
1 2 3 4 5 6 7 8 9 10 11 | var stack = new Stack<Unit>(); stack.push(firstUnit); while( !stack.Any() ) { var item = stack.pop(); //do something here with the item foreach(var child in item.Children) { stack.push(child); } } |
。
这样的算法:
1 2 3 4 | def traverse(Unit i): for (Unit child : i.childList): // Perform your logic for child traverse(child) |
这将为第一个节点的每个子节点执行相同的功能,当应用于i.child[j]时,它将为所有i.child[j].child[k]执行相同的功能,因此它将为每个节点及其所有子节点执行您想要的操作。
相反,您可以使用堆栈:
1 2 3 4 5 6 7 | stack s; s.push(firstNode); while(!stack.empty()): t = stack.pop() foreach(Unit child : t): s.push(child) // Perform logic for child |
号
另一种不使用递归或操作/lambda的方法是使用带有要处理的项的列表。
这样地。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var toDoList = new List<Unit> { unit }; while (toDoList.Any()) { // Get current child, and remove it from the to-do-list var currentChild = toDoList.First(); toDoList.RemoveAt(0); // Do something with the current child. // ... // Now see, if the child has any children to handle if (currentChild.ChildUnits != null && currentChild.ChildUnits.Any()) { toDoList.AddRange(currentChild.ChildUnits); } } |
。