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

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

Creating Map From Changelog With Path in Slice of Strings (Maybe append to map!?)

问题

我有一个类似这样的变更切片:

  1. type Change struct {
  2. Type string // 检测到的变更类型;可以是 create、update 或 delete 之一
  3. Path []string // 检测到的变更路径;将包含遍历过程中的任何字段名或数组索引
  4. From interface{} // “from” 结构中原始值
  5. To interface{} // “to” 结构中检测到的新值
  6. }

我想要根据这个切片创建一个新的 map[string]interface{}

我意识到在遍历路径时,我需要在之前的路径基础上进行构建,但我不确定如何做到这一点。例如,具有以下路径的 Path:{"one": {"two": {"three": "value"}}},对应的 []string 应该是 ["one", "two", "three"]

目前我有以下代码:

  1. for _, change := range changeLog {
  2. for i, _ := range change.Path {
  3. changeMap[change.Path[i]] = make(map[string]interface{})
  4. if i == len(change.Path)-1 {
  5. if castMap, ok := change.To.(map[string]interface{}); ok {
  6. changeMap[p] = castMap
  7. }
  8. }
  9. }
  10. }

但这个代码没有考虑到父级,因此结果是一个扁平的结构。我应该如何实现我想要的结果?

英文:

I have a slice of changes that looks like this:

  1. type Change struct {
  2. Type string // The type of change detected; can be one of create, update or delete
  3. Path []string // The path of the detected change; will contain any field name or array index that was part of the traversal
  4. From interface{} // The original value that was present in the "from" structure
  5. To interface{} // The new value that was detected as a change in the "to" structure
  6. }

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:

  1. for _, change := range changeLog {
  2. for i, _ := range change.Path {
  3. changeMap[change.Path[i]] = make(map[string]interface{})
  4. if i == len(change.Path)-1 {
  5. if castMap, ok := change.To.(map[string]interface{}); ok {
  6. changeMap

    = castMap

  7. }

  8. }

  9. }

  10. }

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切片构建了一棵树。

  1. package main
  2. import (
  3. "fmt"
  4. "strings"
  5. )
  6. type Change struct {
  7. Type string // 检测到的更改类型;可以是create、update或delete之一
  8. Path []string // 检测到的更改路径;将包含遍历过程中的任何字段名或数组索引
  9. From interface{} // “from”结构中原始值
  10. To interface{} // “to”结构中检测到的新值
  11. }
  12. type Node struct {
  13. Children map[string]*Node
  14. To interface{}
  15. }
  16. // 打印树的辅助函数
  17. func (n Node) Print(ident int) {
  18. id := strings.Repeat(" ", ident)
  19. fmt.Println(id+"To:", n.To)
  20. for key, value := range n.Children {
  21. fmt.Println(id + "[" + key + "]")
  22. value.Print(ident + 2)
  23. }
  24. }
  25. func main() {
  26. changeLog := make([]Change, 0)
  27. changeLog = append(changeLog, Change{
  28. Type: "update",
  29. Path: []string{"a", "b"},
  30. From: 1,
  31. To: 2,
  32. })
  33. changeLog = append(changeLog, Change{
  34. Type: "update",
  35. Path: []string{"a", "c"},
  36. From: 3,
  37. To: 4,
  38. })
  39. var node *Node
  40. root := &Node{
  41. Children: make(map[string]*Node),
  42. To: nil,
  43. }
  44. for _, change := range changeLog {
  45. node = root
  46. for _, p := range change.Path {
  47. if _, found := node.Children[p]; !found {
  48. node.Children[p] = &Node{
  49. Children: make(map[string]*Node),
  50. To: nil,
  51. }
  52. }
  53. node = node.Children[p]
  54. }
  55. node.To = change.To
  56. }
  57. // 注意:如果你尝试以这种方式获取一个不存在的路径,将会引发panic!
  58. // 你应该编写一个函数来获取路径的值,如果路径不存在则返回nil。
  59. fmt.Println(root.Children["a"].Children["b"].To)
  60. fmt.Println(root.Children["a"].Children["c"].To)
  61. root.Print(0)
  62. }

输出:

  1. To: <nil>
  2. [a]
  3. To: <nil>
  4. [b]
  5. To: 2
  6. [c]
  7. 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.

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;strings&quot;
  5. )
  6. type Change struct {
  7. Type string // The type of change detected; can be one of create, update or delete
  8. Path []string // The path of the detected change; will contain any field name or array index that was part of the traversal
  9. From interface{} // The original value that was present in the &quot;from&quot; structure
  10. To interface{} // The new value that was detected as a change in the &quot;to&quot; structure
  11. }
  12. type Node struct {
  13. Children map[string]*Node
  14. To interface{}
  15. }
  16. //Helper for printing the tree
  17. func (n Node) Print(ident int) {
  18. id := strings.Repeat(&quot; &quot;, ident)
  19. fmt.Println(id+&quot;To:&quot;, n.To)
  20. for key, value := range n.Children {
  21. fmt.Println(id + &quot;[&quot; + key + &quot;]&quot;)
  22. value.Print(ident + 2)
  23. }
  24. }
  25. func main() {
  26. changeLog := make([]Change, 0)
  27. changeLog = append(changeLog, Change{
  28. Type: &quot;update&quot;,
  29. Path: []string{&quot;a&quot;, &quot;b&quot;},
  30. From: 1,
  31. To: 2,
  32. })
  33. changeLog = append(changeLog, Change{
  34. Type: &quot;update&quot;,
  35. Path: []string{&quot;a&quot;, &quot;c&quot;},
  36. From: 3,
  37. To: 4,
  38. })
  39. var node *Node
  40. root := &amp;Node{
  41. Children: make(map[string]*Node),
  42. To: nil,
  43. }
  44. for _, change := range changeLog {
  45. node = root
  46. for _, p := range change.Path {
  47. if _, found := node.Children

    ; !found {

  48. node.Children

    = &amp;Node{

  49. Children: make(map[string]*Node),

  50. To: nil,

  51. }

  52. }

  53. node = node.Children

  54. }

  55. node.To = change.To

  56. }

  57. //Note: if you try to get a non-exist path this way, the following will panic!

  58. //You should make a func to get the value of a path or get nil back if path not exists.

  59. fmt.Println(root.Children[&quot;a&quot;].Children[&quot;b&quot;].To)

  60. fmt.Println(root.Children[&quot;a&quot;].Children[&quot;c&quot;].To)

  61. root.Print(0)

  62. }

Try it on goplay.space

Output:

  1. To: &lt;nil&gt;
  2. [a]
  3. To: &lt;nil&gt;
  4. [b]
  5. To: 2
  6. [c]
  7. 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:

确定