如何在Go中从map生成父子层级的JSON格式树结构
解决方案
1. 修复结构体定义
你原有结构体的字段首字母为小写,属于Go语言的未导出字段,json序列化时会被直接忽略,同时字段名也不符合预期输出的格式,需要修改为:
type Nodes struct { Funcname string `json:"Funcname"` Nodes []*Nodes `json:"Nodes"` }
2. 核心构建逻辑
整个构建流程时间复杂度为O(n),适配大数据量、多层级场景,不会出现递归栈溢出问题:
- 第一步:找根节点:所有从未作为子节点出现的key就是根节点(常规业务场景下仅有一个根)
- 第二步:创建所有节点的缓存映射,避免重复实例化节点,提升处理效率
- 第三步:遍历原map,给每个父节点绑定对应的子节点列表
3. 完整可运行代码
package main import ( "encoding/json" "log" ) type Nodes struct { Funcname string `json:"Funcname"` Nodes []*Nodes `json:"Nodes"` } func main() { var m map[string][]string m = make(map[string][]string) // 父节点为key,对应子节点列表为value m["root_node"] = []string{"1", "2", "3", "4"} m["1"] = []string{"5", "6"} m["2"] = []string{"7"} m["3"] = []string{"8", "9"} m["5"] = []string{"10"} m["7"] = []string{"11"} m["8"] = []string{"12", "13"} // 1. 收集所有子节点,筛选根节点 childSet := make(map[string]struct{}) for _, children := range m { for _, child := range children { childSet[child] = struct{}{} } } // 根节点特征:不存在于子节点集合中 var root *Nodes nodeCache := make(map[string]*Nodes) for parent := range m { if _, ok := childSet[parent]; !ok { root = &Nodes{Funcname: parent} nodeCache[parent] = root break } } // 2. 初始化所有节点存入缓存,避免重复创建 for parent, children := range m { if _, ok := nodeCache[parent]; !ok { nodeCache[parent] = &Nodes{Funcname: parent} } for _, child := range children { if _, ok := nodeCache[child]; !ok { nodeCache[child] = &Nodes{Funcname: child} } } } // 3. 绑定父子节点关系 for parent, children := range m { pNode := nodeCache[parent] for _, child := range children { cNode := nodeCache[child] pNode.Nodes = append(pNode.Nodes, cNode) } } // 序列化输出,MarshalIndent用于生成格式化的JSON,和你预期的格式完全匹配 bytes, err := json.MarshalIndent(root, "", " ") if err != nil { log.Fatal(err) } log.Println(string(bytes)) }
4. 关于是否需要补充信息的说明
只要你的输入map满足以下条件,就不需要补充额外信息:
- 不存在环形引用(比如A的子节点是B,B的子节点是A)
- 仅有一个根节点(如果是多根场景,自行指定需要输出的根节点即可)
- 所有子节点都能在map中找到对应关系(如果存在孤立子节点,可根据业务需求决定是否要挂载到默认根节点下)
内容的提问来源于stack exchange,提问作者user248396
相关产品推荐
相关产品推荐

