递归循环遍历任意数量的嵌套地图。

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

Loop recursively through an arbitrary number of maps nested

问题

我有一个返回任意层级嵌套的任意数量地图的 API。一个例子:

data=map[a:map[first_seen:2021-10-20 values:[map[h:<nil> ip:142.250.188.206 ip_count:474360 ip_organization:Google LLC]]] aaaa:map[first_seen:2021-10-20 values:[map[h:<nil> ipv6:2607:f8b0:4004:836::200e ipv6_count:459302 ipv6_organization:<nil>]]] mx:map[first_seen:2021-08-04 values:[map[hostname:aspmx.l.google.com hostname_count:1.3895903e+07 hostname_organization:Google LLC priority:10] map[hostname:alt4.aspmx.l.google.com hostname_count:8.616356e+06 hostname_organization:Google LLC priority:50] map[hostname:alt3.aspmx.l.google.com hostname_count:8.676906e+06 hostname_organization:Google LLC priority:40] map[hostname:alt2.aspmx.l.google.com hostname_count:1.3572714e+07 hostname_organization:Google LLC priority:30] map[hostname:alt1.aspmx.l.google.com hostname_count:1.3653905e+07 hostname_organization:Google LLC priority:20]]] ns:map[first_seen:2021-02-28 values:[map[nameserver:ns4.google.com nameserver_count:5320 nameserver_organization:Google LLC] map[nameserver:ns3.google.com nameserver_count:5328 nameserver_organization:Google LLC] map[nameserver:ns2.google.com nameserver_count:5357 nameserver_organization:Google LLC] map[nameserver:ns1.google.com nameserver_count:5386 nameserver_organization:Google LLC]]] soa:map[first_seen:2021-02-28 values:[map[email:dns-admin.google.com email_count:142373 ttl:900]]] txt:map[first_seen:2021-04-22 values:[map[value:v=spf1 include:_spf.google.com ~all] map[value:google-site-verification=wD8N7i1JTNTkezJ49swvWW48f8_9xveREV4oB-0Hf5o] map[value:google-site-verification=TV9-DBe4R80X4v0M4U_bd_J9cpOJM0nikft0jAgjmsQ] map[value:globalsign-smime-dv=CDYX+XFHUw2wml6/Gb8+59BsH31KzUr6c1l2BPvqKX8=] map[value:facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95] map[value:docusign=1b0a6754-49b1-4db5-8540-d2c12664b289] map[value:docusign=05958488-4752-4ef2-95eb-aa7ba8a3bd0e] map[value:apple-domain-verification=30afIBcvSuDV2PLX] map[value:MS=E4A68B9AB2BB9670BCE15412F62916164C0B20BB]]]]

如何递归地循环遍历这样的数据结构?如何获取最深层级地图的键和值?

英文:

I have an API that's returning an arbitrary number of maps nested an arbitrary number of levels deep. One example:

data=map[a:map[first_seen:2021-10-20 values:[map[h:<nil> ip:142.250.188.206 ip_count:474360 ip_organization:Google LLC]]] aaaa:map[first_seen:2021-10-20 values:[map[h:<nil> ipv6:2607:f8b0:4004:836::200e ipv6_count:459302 ipv6_organization:<nil>]]] mx:map[first_seen:2021-08-04 values:[map[hostname:aspmx.l.google.com hostname_count:1.3895903e+07 hostname_organization:Google LLC priority:10] map[hostname:alt4.aspmx.l.google.com hostname_count:8.616356e+06 hostname_organization:Google LLC priority:50] map[hostname:alt3.aspmx.l.google.com hostname_count:8.676906e+06 hostname_organization:Google LLC priority:40] map[hostname:alt2.aspmx.l.google.com hostname_count:1.3572714e+07 hostname_organization:Google LLC priority:30] map[hostname:alt1.aspmx.l.google.com hostname_count:1.3653905e+07 hostname_organization:Google LLC priority:20]]] ns:map[first_seen:2021-02-28 values:[map[nameserver:ns4.google.com nameserver_count:5320 nameserver_organization:Google LLC] map[nameserver:ns3.google.com nameserver_count:5328 nameserver_organization:Google LLC] map[nameserver:ns2.google.com nameserver_count:5357 nameserver_organization:Google LLC] map[nameserver:ns1.google.com nameserver_count:5386 nameserver_organization:Google LLC]]] soa:map[first_seen:2021-02-28 values:[map[email:dns-admin.google.com email_count:142373 ttl:900]]] txt:map[first_seen:2021-04-22 values:[map[value:v=spf1 include:_spf.google.com ~all] map[value:google-site-verification=wD8N7i1JTNTkezJ49swvWW48f8_9xveREV4oB-0Hf5o] map[value:google-site-verification=TV9-DBe4R80X4v0M4U_bd_J9cpOJM0nikft0jAgjmsQ] map[value:globalsign-smime-dv=CDYX+XFHUw2wml6/Gb8+59BsH31KzUr6c1l2BPvqKX8=] map[value:facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95] map[value:docusign=1b0a6754-49b1-4db5-8540-d2c12664b289] map[value:docusign=05958488-4752-4ef2-95eb-aa7ba8a3bd0e] map[value:apple-domain-verification=30afIBcvSuDV2PLX] map[value:MS=E4A68B9AB2BB9670BCE15412F62916164C0B20BB]]]]

How can I loop recursively through such a data structure? How do I get to the key, value of the map at the deepest level?

答案1

得分: 1

如果这是一个JSON响应,我有一个适用的包:

package main

import (
   "fmt"
   "github.com/89z/parse/json"
)

var data = []byte(`
{
   "soa": {
      "values":[
         {"email_count":142373, "ttl":900}
      ]
   }
}
`)

func main() {
   var values []struct {
      Email_Count int
      TTL int
   }
   if err := json.UnmarshalArray(data, &values); err != nil {
      panic(err)
   }
   fmt.Printf("%+v\n", values) // [{Email_Count:142373 TTL:900}]
}

https://github.com/89z/parse

英文:

If it's a JSON response, I have a package for that:

package main

import (
   "fmt"
   "github.com/89z/parse/json"
)

var data = []byte(`
{
   "soa": {
      "values":[
         {"email_count":142373, "ttl":900}
      ]
   }
}
`)

func main() {
   var values []struct {
      Email_Count int
      TTL int
   }
   if err := json.UnmarshalArray(data, &values); err != nil {
      panic(err)
   }
   fmt.Printf("%+v\n", values) // [{Email_Count:142373 TTL:900}]
}

https://github.com/89z/parse

答案2

得分: 1

这是一个简单的深度优先地图遍历器,类似这样的代码应该适合你的需求。它在每个叶节点("叶子"被定义为"非地图")上调用回调函数visit(),并传递以下参数:

  • 包含路径的切片/数组(指向该项的键的路径)
  • 该项的键
  • 该项的值
type Visit func(path []interface{}, key interface{}, value interface{})

func MapWalker(data map[interface{}]interface{}, visit Visit) {
  traverse(data, []interface{}{}, visit)
}

func traverse(data map[interface{}]interface{}, path []interface{}, visit Visit) {

  for key, value := range data {

    if child, isMap := value.(map[interface{}]interface{}); isMap {

      path = append(path, key)
      traverse(child, path, visit)
      path = path[:len(path)-1]

    } else {

      visit(path, key, child)

    }

  }

}

使用方法非常简单:


func do_something_with_item(path []interface{}, key, value interface{}) {
  // path是一个interface{}切片(指向当前对象的键的路径)
  // key是当前属性的名称(作为interface{})
  // value是当前值,同样是interface{}
  //
  // 你需要将这些interface{}转换为可用的类型
}

MapWalker(someGenericMapOfGenericMaps, do_something_with_item)

每当在树中遇到一个叶节点时,都会调用do_something_with_item()函数。

英文:

Something like this ought to do you — simple depth-first map walker. It invokes you callback function visit() on every leaf node ("leaf" being defined as "not a map"), passing it

  • A slice/array containing the path (the keys leading to the item),
  • The item's key, and
  • The item's value
type Visit func( path []interface{}, key interface{}, value interface{} )

func MapWalker( data map[interface{}]interface{}, visit Visit ) {
  traverse( data, []interface{}{}, visit )
}

func traverse( data map[interface{}]interface{}, path []interface{}, visit Visit ) {

  for key, value := range data {

    if child, isMap := value.(map[interface{}]interface{}); isMap {

      path = append( path, key )
      traverse( child, path, visit )
      path = path[:len(path)-1]

    } else {

      visit( path, key, child )

    }

  }

}

Usage is pretty simple:


func do_something_with_item( path []interface{}, key, value interface{} ) {
  // path is a slice of interface{} (the keys leading to the current object
  // key is the name of the current property (as an interface{})
  // value is the current value, agains as an interface{}
  //
  // Again it's up to you to cast these interface{} to something usable
}

MapWalker( someGenericMapOfGenericMaps, do_something_with_item )

Every time a leaf node is encountered in the tree, your do_something_with_item() function will be invoked.

huangapple
  • 本文由 发表于 2021年10月21日 06:31:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/69653746.html
匿名

发表评论

匿名网友

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

确定