You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中含层级关联的Parameter数组转换为字典的算法实现疑问

如何将带有父子关系的Parameter数组转换为嵌套字典(支持无序数组)

我正在尝试将一个包含父子关系的Parameter结构体数组转换为嵌套字典,但在处理带有parent的元素时遇到了困难,尤其是当数组无序(子节点可能比父节点先出现)的情况。

场景说明

我的Parameter结构体定义如下:

struct Parameter {
    let type: String
    let name: String
    let value: Any
    let parent: String?
}

示例输入数组:

let array = [
    Parameter(type: "string", name: "name1", value: "bar", parent: nil),
    Parameter(type: "bool", name: "name2", value: true, parent: nil),
    Parameter(type: "array", name: "name3", value: [], parent: nil),
    Parameter(type: "bool", name: "name3.1", value: false, parent: "name3"),
    Parameter(type: "array", name: "name3.2", value: [], parent: "name3"),
    Parameter(type: "string", name: "name4.1", value: "baz", parent: "name3.2")
]

期望输出的嵌套字典:

[
    "name1": "bar",
    "name2": true,
    "name3": [
        "name3.1": false,
        "name3.2": [
            "name4.1": "baz"
        ]
    ]
]

我目前的代码只能处理无parent的根节点,不知道如何处理有父节点的情况,尤其是数组无序时子节点先被遍历到的场景:

func makeDictionary(from array: [Parameter]) -> [String: Any] {
    var dictionary: [String: Any] = [:]
    for parameter in array {
        if let parent = parameter.parent {
            #warning("how to handle this case?")
        } else {
            dictionary[parameter.name] = parameter.value
        }
    }
    return dictionary
}

解决方案

核心问题是数组无序导致子节点可能先于父节点被处理,以及需要在嵌套结构中准确定位父节点的位置。我们可以通过以下思路解决:

  1. 先建立所有节点的映射表,方便快速查找任意节点(包括父节点);
  2. 使用引用类型的NSMutableDictionary来处理嵌套结构的修改(避免值类型字典的拷贝问题);
  3. 递归创建父节点的容器,确保子节点处理时父容器已经存在;
  4. 避免覆盖已创建的容器(比如父节点的初始值会被子节点创建的容器替换)。

完整实现代码:

struct Parameter {
    let type: String
    let name: String
    let value: Any
    let parent: String?
}

func makeDictionary(from array: [Parameter]) -> [String: Any] {
    let root = NSMutableDictionary()
    // 建立节点名称到节点的映射,快速查找任意节点
    let nodeMap = Dictionary(uniqueKeysWithValues: array.map { ($0.name, $0) })
    
    // 递归函数:获取或创建指定节点的父容器
    func getParentContainer(for nodeName: String) -> NSMutableDictionary? {
        guard let currentNode = nodeMap[nodeName] else { return nil }
        
        if let parentName = currentNode.parent {
            // 先尝试获取父节点的容器
            if let parentContainer = getParentContainer(for: parentName) {
                // 检查父容器中是否已有当前节点的容器,没有则创建
                if let existingContainer = parentContainer[nodeName] as? NSMutableDictionary {
                    return existingContainer
                } else {
                    let newContainer = NSMutableDictionary()
                    parentContainer[nodeName] = newContainer
                    return newContainer
                }
            } else {
                // 父节点不存在,先创建父节点的容器
                guard let parentNode = nodeMap[parentName] else { return nil }
                let parentContainer = NSMutableDictionary()
                // 递归创建父节点的父容器(如果有)
                if let grandparentName = parentNode.parent {
                    getParentContainer(for: grandparentName)?[parentName] = parentContainer
                } else {
                    // 父节点是根节点,直接加入顶层字典
                    root[parentName] = parentContainer
                }
                // 创建当前节点的容器并加入父容器
                let newContainer = NSMutableDictionary()
                parentContainer[nodeName] = newContainer
                return newContainer
            }
        } else {
            // 当前节点是根节点,父容器就是顶层字典
            return root
        }
    }
    
    // 遍历所有节点,加入对应容器
    for parameter in array {
        if let parentName = parameter.parent {
            guard let parentContainer = getParentContainer(for: parentName) else { continue }
            // 如果父容器中已经存在当前节点的容器(子节点先创建的),不覆盖
            if parentContainer[parameter.name] is NSMutableDictionary {
                continue
            }
            parentContainer[parameter.name] = parameter.value
        } else {
            // 根节点如果已经存在容器(子节点先创建的),不覆盖初始值
            if root[parameter.name] is NSMutableDictionary {
                continue
            }
            root[parameter.name] = parameter.value
        }
    }
    
    // 将NSMutableDictionary转换为Swift原生字典返回
    return root as! [String: Any]
}

代码说明

  • 节点映射表:nodeMap让我们可以O(1)时间查找任意节点,避免重复遍历数组;
  • 递归创建容器:getParentContainer会逐层检查并创建父节点的容器,确保子节点处理时父结构已经存在;
  • 避免覆盖容器:当子节点先处理并创建了父节点的容器后,后续处理父节点时不会用初始值(比如[])覆盖已有的容器,保证子节点内容不丢失;
  • 引用类型优势:使用NSMutableDictionary可以直接修改嵌套结构中的字典,不需要处理值类型的拷贝问题,简化了代码逻辑。

内容的提问来源于stack exchange,提问作者dehlen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 04:52:51