如何不使用嵌套循环从深度嵌套XML结构中提取指定Element?
避免嵌套循环提取Go嵌套XML结构中的指定Element
我有一个对应XML的深度嵌套Go结构体定义如下:
type Obj struct{ Scripts []*Script `xml:"scripts"` } type Script struct{ ID string `xml:"id"` Tables []*Table `xml:"tables"` } type Table struct{ Elements []*Element `xml:"elements"` Tables []*Table `xml:"tables"` } type Element struct{ Key string `xml:"key"` Val string `xml:"val"` }
需要从Obj中提取出符合指定Key的Element列表,当前使用多层嵌套循环实现的代码如下:
var elements []*Element for _, s := range obj.Scripts { if s.ID == "requireID"{ for _, table := range s.Tables{ for _, t := range table.Tables{ for _, el := range t.Elements{ if el.Key == "requireKey"{ elements = append(elements, el) } } } } } } }
请问如何不使用嵌套循环完成这一需求?
方案1:递归遍历(代码简洁易读)
由于Table结构体包含自身类型的子节点,属于递归结构,可以编写一个递归函数来遍历所有层级的Table,收集符合条件的Element,彻底消除嵌套循环:
// collectElementsByKey 递归遍历所有层级的Table,返回符合目标Key的Element列表 func collectElementsByKey(tables []*Table, targetKey string) []*Element { var elements []*Element for _, table := range tables { // 收集当前Table中符合条件的Element for _, el := range table.Elements { if el.Key == targetKey { elements = append(elements, el) } } // 递归处理子Table elements = append(elements, collectElementsByKey(table.Tables, targetKey)...) } return elements }
在主逻辑中调用该函数:
var elements []*Element for _, s := range obj.Scripts { if s.ID == "requireID" { // 直接传入当前Script的Tables,递归收集所有符合条件的Element elements = append(elements, collectElementsByKey(s.Tables, "requireKey")...) } }
这种方式将嵌套遍历逻辑封装到独立函数中,代码结构更清晰,后续如果嵌套结构发生变化,只需修改递归函数即可。
方案2:迭代式遍历(避免递归栈溢出)
如果XML结构嵌套极深,递归可能导致栈溢出,此时可以用广度优先遍历的迭代方式实现:
// collectElementsByKeyIterative 迭代式遍历所有层级的Table,返回符合目标Key的Element列表 func collectElementsByKeyIterative(tables []*Table, targetKey string) []*Element { var elements []*Element // 用队列存储待处理的Table queue := make([]*Table, 0, len(tables)) queue = append(queue, tables...) for len(queue) > 0 { // 取出队列头部的Table table := queue[0] queue = queue[1:] // 收集当前Table的符合条件的Element for _, el := range table.Elements { if el.Key == targetKey { elements = append(elements, el) } } // 将子Table加入队列,等待处理 queue = append(queue, table.Tables...) } return elements }
调用方式和递归版本完全一致,这种方式不会受递归深度限制,适合处理超深嵌套的场景。
内容的提问来源于stack exchange,提问作者vovanchello
相关产品推荐
相关产品推荐

