从更改日志中创建带有路径的字符串切片的映射(也许追加到映射中!?)

huangapple go评论74阅读模式
英文:

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

在goplay.space上试一试

英文:

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 (
&quot;fmt&quot;
&quot;strings&quot;
)
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 &quot;from&quot; structure
To   interface{} // The new value that was detected as a change in the &quot;to&quot; structure
}
type Node struct {
Children map[string]*Node
To       interface{}
}
//Helper for printing the tree
func (n Node) Print(ident int) {
id := strings.Repeat(&quot; &quot;, ident)
fmt.Println(id+&quot;To:&quot;, n.To)
for key, value := range n.Children {
fmt.Println(id + &quot;[&quot; + key + &quot;]&quot;)
value.Print(ident + 2)
}
}
func main() {
changeLog := make([]Change, 0)
changeLog = append(changeLog, Change{
Type: &quot;update&quot;,
Path: []string{&quot;a&quot;, &quot;b&quot;},
From: 1,
To:   2,
})
changeLog = append(changeLog, Change{
Type: &quot;update&quot;,
Path: []string{&quot;a&quot;, &quot;c&quot;},
From: 3,
To:   4,
})
var node *Node
root := &amp;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

= &amp;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[&quot;a&quot;].Children[&quot;b&quot;].To) fmt.Println(root.Children[&quot;a&quot;].Children[&quot;c&quot;].To) root.Print(0) }

Try it on goplay.space

Output:

To: &lt;nil&gt;
[a]
To: &lt;nil&gt;
[b]
To: 2
[c]
To: 4

huangapple
  • 本文由 发表于 2022年4月10日 02:06:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/71810654.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定