如何遍历多层嵌套WorkItemClassificationNode集合?避免嵌套循环
这问题我之前处理树形嵌套结构的时候也碰到过!完全不用写一堆嵌套循环,递归或者迭代式的遍历(深度/广度优先)都是非常优雅的解决方案,给你具体拆解下怎么实现:
方法一:递归实现(最直观易写)
递归简直是为这种嵌套结构量身定做的——处理当前节点后,再递归处理它的所有子节点,逻辑清晰到一眼就能看懂。
举个C#的实现示例:
// 定义处理单个节点的逻辑方法 private void ProcessNode(WorkItemClassificationNode node) { // 这里写你要对每个节点执行的逻辑,比如打印、修改属性等 Console.WriteLine($"处理节点:{node.Name}"); } // 递归遍历所有层级的方法 private void TraverseAllNodes(IEnumerable<WorkItemClassificationNode> nodes) { if (nodes == null || !nodes.Any()) return; foreach (var node in nodes) { // 先处理当前节点 ProcessNode(node); // 再递归处理它的子节点 TraverseAllNodes(node.Children); } } // 调用方式 TraverseAllNodes(items);
优点:代码极简,逻辑直观,几乎不用动脑子就能写出来。
小提醒:如果你的嵌套层级特别深(比如上千层),可能会触发栈溢出异常,但一般业务场景里这种情况很少见。
方法二:迭代式遍历(避免栈溢出风险)
要是担心递归的栈溢出问题,或者需要处理超深层级的结构,那迭代式的遍历就更稳妥了,核心是用集合(栈/队列)来模拟递归的调用栈。
2.1 深度优先遍历(用Stack)
和递归的遍历顺序一致,先深入到最底层的子节点,再回溯处理兄弟节点:
private void TraverseAllNodesDepthFirst(IEnumerable<WorkItemClassificationNode> rootNodes) { if (rootNodes == null || !rootNodes.Any()) return; var stack = new Stack<WorkItemClassificationNode>(); // 先把根节点都压入栈,Reverse保证遍历顺序和递归一致 foreach (var node in rootNodes.Reverse()) { stack.Push(node); } while (stack.Count > 0) { var currentNode = stack.Pop(); // 处理当前节点 ProcessNode(currentNode); // 把子节点倒序压入栈,这样弹出的时候是正序 if (currentNode.Children != null && currentNode.Children.Any()) { foreach (var child in currentNode.Children.Reverse()) { stack.Push(child); } } } }
2.2 广度优先遍历(用Queue)
按层级从上到下遍历,先处理所有根节点,再处理第一层子节点,接着第二层,以此类推:
private void TraverseAllNodesBreadthFirst(IEnumerable<WorkItemClassificationNode> rootNodes) { if (rootNodes == null || !rootNodes.Any()) return; var queue = new Queue<WorkItemClassificationNode>(); foreach (var node in rootNodes) { queue.Enqueue(node); } while (queue.Count > 0) { var currentNode = queue.Dequeue(); // 处理当前节点 ProcessNode(currentNode); // 把子节点依次入队 if (currentNode.Children != null && currentNode.Children.Any()) { foreach (var child in currentNode.Children) { queue.Enqueue(child); } } } }
进阶:封装成可复用的扩展方法
如果需要多次用到这个遍历逻辑,还可以把扁平化的逻辑封装成扩展方法,这样用起来更丝滑:
public static class WorkItemExtensions { // 深度优先扁平化所有节点 public static IEnumerable<WorkItemClassificationNode> FlattenDepthFirst(this IEnumerable<WorkItemClassificationNode> nodes) { if (nodes == null) yield break; foreach (var node in nodes) { yield return node; // 递归扁平化子节点 foreach (var child in node.Children.FlattenDepthFirst()) { yield return child; } } } // 广度优先扁平化所有节点 public static IEnumerable<WorkItemClassificationNode> FlattenBreadthFirst(this IEnumerable<WorkItemClassificationNode> nodes) { if (nodes == null) yield break; var queue = new Queue<WorkItemClassificationNode>(nodes); while (queue.Count > 0) { var node = queue.Dequeue(); yield return node; if (node.Children != null) { foreach (var child in node.Children) { queue.Enqueue(child); } } } } } // 调用方式超简单! foreach (var node in items.FlattenDepthFirst()) { ProcessNode(node); }
这样不管嵌套多少层,都能一行代码拿到所有节点,然后统一处理逻辑,完全不用写嵌套循环~
内容的提问来源于stack exchange,提问作者bdtrfs
相关产品推荐
相关产品推荐

