如何在嵌套Places结构体列表中递归查找指定ID的结构体?
递归查找嵌套结构体中的目标元素
当然可以搞定这个问题!因为你的地点结构体是嵌套层级的,普通的filter只能处理第一层节点,用递归就能遍历所有深度的子节点,精准找到目标ID的结构体。
首先,我们需要确保PlacesProtocol里定义了递归查找需要的核心属性(如果还没定义的话):
protocol PlacesProtocol { var id: String { get } var childPlaces: [PlacesProtocol]? { get } // 如果需要直接访问名称,也可以把name加入协议 var name: String { get } }
接下来,给PlacesProtocol扩展一个递归查找方法,这样所有遵循该协议的类型都能直接调用这个方法,非常优雅:
extension PlacesProtocol { func findPlace(byTargetId targetId: String) -> PlacesProtocol? { // 先检查当前节点是否是目标 if self.id == targetId { return self } // 遍历所有子节点,递归查找 if let childPlaces = self.childPlaces { for child in childPlaces { if let foundPlace = child.findPlace(byTargetId: targetId) { return foundPlace } } } // 所有节点遍历完都没找到,返回nil return nil } }
这个方法的逻辑很直观:
- 先判断当前结构体的ID是否匹配目标,匹配就直接返回自己
- 如果不匹配,就遍历当前节点的所有子节点,对每个子节点递归调用查找方法
- 一旦在某个子节点或它的后代中找到目标,就立即返回结果;全程没找到就返回
nil
使用示例
假设你已经把JSON解析成了根节点rootPlace,直接调用方法即可:
// 查找ID为"13"的地点 if let targetPlace = rootPlace.findPlace(byTargetId: "13") as? Places { print("找到目标地点:ID = \(targetPlace.id),名称 = \(targetPlace.name)") } else { print("未找到指定ID的地点") }
这里把返回的PlacesProtocol转成Places类型,是为了直接访问name属性——如果你的协议里已经定义了name,就不需要强制转换了。
如果需要一次性找到所有匹配ID的节点(虽然ID应该是唯一的,但以防万一),可以修改方法返回数组:
extension PlacesProtocol { func findAllPlaces(byTargetId targetId: String) -> [PlacesProtocol] { var results = [PlacesProtocol]() if self.id == targetId { results.append(self) } if let childPlaces = self.childPlaces { for child in childPlaces { results.append(contentsOf: child.findAllPlaces(byTargetId: targetId)) } } return results } }
内容的提问来源于stack exchange,提问作者Vijay
相关产品推荐
相关产品推荐

