Как создать дерево (родитель-потомок) в формате json из карты

# #go #data-structures #tree

Вопрос:

Чего я хочу?

Чтобы получить дерево в формате JSON с карты.

Данные, которые будут использоваться:

Карта (пары ключ-значение), имеющая ключи в качестве родителей и их соответствующие значения в качестве детей

Код: В следующем коде используются примеры данных, я хочу использовать большие данные позже, это означает, что у меня будет больше родителей-детей. Как я могу структурировать отношения родитель-потомок на основе карты? Пожалуйста, дайте мне знать, нужна ли мне какая-либо другая информация для анализа картографических данных в древовидную структуру?

 type Nodes struct  {
      fn string
      children []*Nodes
}

func main() {
    var m map[string][]string
    m = make(map[string][]string)
    //map of parents(key) and child(values)
    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"}

//json format: I don't know how to get root_node so expected result can be achieved
bytes, err := json.Marshal(root_node)
if err != nil {
    log.Fatal(err)
}
}
 

Мои ожидания:

 {
   "Funcname": "root_node",
   "Nodes": [
      {
         "Funcname": "1",
         "Nodes": [
            {
               "Funcname": "5",
               "Nodes": [
                  {
                     "Funcname": "10",
                     "Nodes": null
                  }
               ]
            },
            {
               "Funcname": "6",
               "Nodes": null
            }
         ]
      },
      {
         "Funcname": "2",
         "Nodes": [
            {
               "Funcname": "7",
               "Nodes": [
                  {
                     "Funcname": "11",
                     "Nodes": null
                  }
               ]
            }
         ]
      },
      {
         "Funcname": "3",
         "Nodes": [
            {
               "Funcname": "8",
               "Nodes": [
                  {
                     "Funcname": "12",
                     "Nodes": null
                  },
                  {
                     "Funcname": "13",
                     "Nodes": null
                  }
               ]
            },
            {
               "Funcname": "9",
               "Nodes": null
            }
         ]
      },
      {
         "Funcname": "4",
         "Nodes": null
      }
   ]
}
 

Ответ №1:

более простой подход

Мы также можем сказать, что это более чистый подход-создавать узлы с синтаксисом конструктора.

 type Node struct {
    Name     string
    Children []*Node
}

func first_example() {
    root := Node{
        Name: "1",
        Children: []*Node{
            {
                Name: "3",
                Children: []*Node{
                    {
                        Name: "5",
                    },
                },
            },
        },
    }

    bytes, err := json.Marshal(root)
    if err != nil {
        panic(err)
    }

    fmt.Println(string(bytes))
}
 

более жесткий подход

Результат тот же, но он намного более динамичен и позволяет хранить дополнительные значения, с другой стороны, обход дерева намного более раздражает, так как вам всегда приходится все разыгрывать.

 func second_example() {
    root := map[string]interface{}{
        "Name": "1",
        "Children": []map[string]interface{}{
            {
                "Name": "3",
                "Children": []map[string]interface{}{
                    {
                        "Name": "5",
                    },
                },
            },
        },
    }

    bytes, err := json.Marshal(root)
    if err != nil {
        panic(err)
    }

    fmt.Println(string(bytes))
}
 

выход

 {"Name":"1","Children":[{"Name":"3","Children":[{"Name":"5","Children":null}]}]} // #1
{"Children":[{"Children":[{"Name":"5"}],"Name":"3"}],"Name":"1"} // #2
 

Редактировать

Кроме того, здесь есть функция вставки узла в структуру. Значение False возвращается в случае сбоя операции.

 func (n *Node) InsertNode(path string, o *Node) bool {
    parts := strings.Split(path, " ")
    target := n
    for _, part := range parts {
        found := false
        for _, child := range target.Children {
            if child.Name == part {
                target = child
                found = true
                break
            }
        }
        if !found {
            return false
        }
    }

    target.Children = append(target.Children, o)
    return true
}

func third_example() {
    root := amp;Node{Name: "1"}
    root.Children = append(root.Children, amp;Node{Name: "3"})
    root.InsertNode("3", amp;Node{Name: "5"})

    bytes, err := json.Marshal(root)
    if err != nil {
        panic(err)
    }

    fmt.Println(string(bytes))
}
 

Комментарии:

1. Спасибо за ваш ответ, но я хочу пройти по карте, а затем создать узлы дерева без необходимости вручную вводить каждое значение в структуру. Может быть, с помощью диапазона или рекурсии, что меня очень смущает.

2. Итак, вам нужен метод на узле, который может вставлять новый узел не только на верхний уровень?

3. да, мне нужен метод, который может добавлять данные с карты в узлы, а затем пересекать эти узлы, чтобы сформировать иерархию, а затем, наконец, отобразить иерархию в формате json.

4. @user248396 Я добавил решение

Ответ №2:

Сначала определите Node тип с AddChild() помощью метода —

 type Node struct {
    Fn       string  `json:"Funcname"`
    Children []*Node `json:"Nodes"`
}

func (node *Node) AddChild(child *Node) {
    node.Children = append(node.Children, child)
}
 

Функция конструктора для построения нового узла для данного fn

 func CreateNewNode(fn string) *Node {
    newNode := new(Node)
    newNode.Fn = fn
    return newNode
}
 

Чтобы сгенерировать дерево на основе карты, определите MakeTreeFromMap() функцию следующим образом —

 // MakeTreeFromMap generates a tree from given map and returns pointer to root node of tree.
func MakeTreeFromMap(treeMap map[string][]string, rootNodeFn string) *Node {
    cache := make(map[string]*Node)
    for fn, children := range treeMap {
        if _, nodeExists := cache[fn]; !nodeExists {
            node := CreateNewNode(fn)
            cache[fn] = node
        }
        for _, childFn := range children {
            if _, childExists := cache[childFn]; !childExists {
                child := CreateNewNode(childFn)
                cache[childFn] = child
            }
            cache[fn].AddChild(cache[childFn])
        }
    }
    return cache[rootNodeFn]
}
 

Сериализовать дерево в JSON —

 root_node := MakeTreeFromMap(m, "root_node")
bytes, err := json.Marshal(root_node)
if err != nil {
    log.Fatal(err)
}
 

Полный рабочий пример см. в разделе Игровая площадка Go.