英文:
Creating Map From Changelog With Path in Slice of Strings (Maybe append to map!?)
问题
我有一个类似这样的变更切片:
type Change struct {
Type string // 检测到的变更类型;可以是 create、update 或 delete 之一
Path []string // 检测到的变更路径;将包含遍历过程中的任何字段名或数组索引
From interface{} // “from” 结构中原始值
To interface{} // “to” 结构中检测到的新值
}
我想要根据这个切片创建一个新的 map[string]interface{}
。
我意识到在遍历路径时,我需要在之前的路径基础上进行构建,但我不确定如何做到这一点。例如,具有以下路径的 Path:{"one": {"two": {"three": "value"}}}
,对应的 []string
应该是 ["one", "two", "three"]
。
目前我有以下代码:
for _, change := range changeLog {
for i, _ := range change.Path {
changeMap[change.Path[i]] = make(map[string]interface{})
if i == len(change.Path)-1 {
if castMap, ok := change.To.(map[string]interface{}); ok {
changeMap[p] = castMap
}
}
}
}
但这个代码没有考虑到父级,因此结果是一个扁平的结构。我应该如何实现我想要的结果?
英文:
I have a slice of changes that looks like this:
type Change struct {
Type string // The type of change detected; can be one of create, update or delete
Path []string // The path of the detected change; will contain any field name or array index that was part of the traversal
From interface{} // The original value that was present in the "from" structure
To interface{} // The new value that was detected as a change in the "to" structure
}
I'm trying to take this and create a new map[string]interface{}
from this.
I realized looping through path I'd need to build upon the prior path but I'm unsure how to do this. E.g. Path with this: {"one": {"two": {"three": "value"}}}
would have []string{"one", "two", "three"}
Right now I have this code:
for _, change := range changeLog {
for i, _ := range change.Path {
changeMap[change.Path[i]] = make(map[string]interface{})
if i == len(change.Path)-1 {
if castMap, ok := change.To.(map[string]interface{}); ok {
changeMap = castMap
}
}
}
}
But this doesn't account for the parents hence the result is a flat structure. How do I achieve what I'm trying to achieve.
答案1
得分: 1
如果你想将你的Change切片转换为基于map的树结构,你应该使用一些节点结构来保存树的数据,因为一个变量不能同时保存一个map和一个接口(To值)。我创建了一个可以工作的示例,并根据你的changelog切片构建了一棵树。
package main
import (
"fmt"
"strings"
)
type Change struct {
Type string // 检测到的更改类型;可以是create、update或delete之一
Path []string // 检测到的更改路径;将包含遍历过程中的任何字段名或数组索引
From interface{} // “from”结构中原始值
To interface{} // “to”结构中检测到的新值
}
type Node struct {
Children map[string]*Node
To interface{}
}
// 打印树的辅助函数
func (n Node) Print(ident int) {
id := strings.Repeat(" ", ident)
fmt.Println(id+"To:", n.To)
for key, value := range n.Children {
fmt.Println(id + "[" + key + "]")
value.Print(ident + 2)
}
}
func main() {
changeLog := make([]Change, 0)
changeLog = append(changeLog, Change{
Type: "update",
Path: []string{"a", "b"},
From: 1,
To: 2,
})
changeLog = append(changeLog, Change{
Type: "update",
Path: []string{"a", "c"},
From: 3,
To: 4,
})
var node *Node
root := &Node{
Children: make(map[string]*Node),
To: nil,
}
for _, change := range changeLog {
node = root
for _, p := range change.Path {
if _, found := node.Children[p]; !found {
node.Children[p] = &Node{
Children: make(map[string]*Node),
To: nil,
}
}
node = node.Children[p]
}
node.To = change.To
}
// 注意:如果你尝试以这种方式获取一个不存在的路径,将会引发panic!
// 你应该编写一个函数来获取路径的值,如果路径不存在则返回nil。
fmt.Println(root.Children["a"].Children["b"].To)
fmt.Println(root.Children["a"].Children["c"].To)
root.Print(0)
}
输出:
To: <nil>
[a]
To: <nil>
[b]
To: 2
[c]
To: 4
英文:
If you want to transverse your slice of Change to a tree struct based on maps, you should use some node struct to hold the tree data, because a variable cannot hold a map and an interface (the To value) at the same time. I make this sample that works and build you a tree based on your changelog slice.
package main
import (
"fmt"
"strings"
)
type Change struct {
Type string // The type of change detected; can be one of create, update or delete
Path []string // The path of the detected change; will contain any field name or array index that was part of the traversal
From interface{} // The original value that was present in the "from" structure
To interface{} // The new value that was detected as a change in the "to" structure
}
type Node struct {
Children map[string]*Node
To interface{}
}
//Helper for printing the tree
func (n Node) Print(ident int) {
id := strings.Repeat(" ", ident)
fmt.Println(id+"To:", n.To)
for key, value := range n.Children {
fmt.Println(id + "[" + key + "]")
value.Print(ident + 2)
}
}
func main() {
changeLog := make([]Change, 0)
changeLog = append(changeLog, Change{
Type: "update",
Path: []string{"a", "b"},
From: 1,
To: 2,
})
changeLog = append(changeLog, Change{
Type: "update",
Path: []string{"a", "c"},
From: 3,
To: 4,
})
var node *Node
root := &Node{
Children: make(map[string]*Node),
To: nil,
}
for _, change := range changeLog {
node = root
for _, p := range change.Path {
if _, found := node.Children; !found {
node.Children
= &Node{
Children: make(map[string]*Node),
To: nil,
}
}
node = node.Children
}
node.To = change.To
}
//Note: if you try to get a non-exist path this way, the following will panic!
//You should make a func to get the value of a path or get nil back if path not exists.
fmt.Println(root.Children["a"].Children["b"].To)
fmt.Println(root.Children["a"].Children["c"].To)
root.Print(0)
}
Output:
To: <nil>
[a]
To: <nil>
[b]
To: 2
[c]
To: 4
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论