我在遍历对象的所有后代时遇到问题。
以下代码中的'unit'
在我的程序中属于Unit
类型。它有一个属性ChildUnits
,它返回单元子级的List<Unit>
。
我可以成功地对孩子们进行操作。然后我检查这些孩子是否有孩子,如果他们这样做,我也可以对他们进行操作。
但是,我需要检查所有后代,以防有更多的深度而不仅仅是孙子。除了下面的代码之外,我还使用了while循环,但是它非常混乱所以我把它留了出来。
这是我恢复的代码:
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.
}
}
}
我可以深入到另一个层次,因为一个单位的深度比这个更深。但那不是一个干净的解决方案。
我想我可能需要使用图遍历算法和/或递归,但我想就如何最有效地解决这个问题提出一些建议。
编辑:是否可以在不定义新功能/方法的情况下执行此操作?
答案 0 :(得分:1)
这样的算法:
def traverse(Unit i):
for (Unit child : i.childList):
// Perform your logic for child
traverse(child)
这将为第一个节点的每个子节点执行相同的功能,并且当将其应用于i.child [j]时,它将为所有i.child [j] .child [k]执行相同的功能,因此它将为每个节点及其所有子节点执行所需的操作。
而你可以使用stack:
stack s;
s.push(firstNode);
while(!stack.empty()):
t = stack.pop()
foreach(Unit child : t):
s.push(child)
// Perform logic for child
答案 1 :(得分:1)
您可以使用递归:
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
}
}
如果您不想定义新方法,您也可以自己堆叠:
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);
}
}
答案 2 :(得分:1)
编辑:是否可以在不定义新功能/方法的情况下执行此操作?
您可以使用匿名方法...这不完全是“未定义新方法”,我知道:)
但是,还有另一个问题需要注意:循环引用...... even if you dont think there will be any
这是一个实现,没有定义任何新方法
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
答案 3 :(得分:0)
在没有递归或action / lambda的情况下执行此操作的另一种方法是使用包含要处理的项的列表。
喜欢这个。
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);
}
}