猿问

Golang:如何创建未知(动态)地图长度

我可以通过创建“静态”地图


type m map[int]map[int]map[int]bool

但“键”的长度将是动态的:


 |---unknown len--|

m[1][2][3][4][2][0] = true

或者


|---unk len--|

m[1][2][3][4] = true

如何在 Go 中创建此地图?或者有什么办法存在?


哈士奇WWW
浏览 173回答 3
3回答

烙印99

该地图类型:映射是一种类型的无序元素组,称为元素类型,由一组另一种类型的唯一键索引,称为键类型。映射类型必须具有特定的值类型和特定的键类型。你想要的不符合这个条件:你想要一个值有时是另一个映射(相同类型)的映射,有时它是一个bool.您的选择:1. 带包装值类型这里的想法是不仅仅使用简单的 ( bool) 值类型,而是使用一个包装器来保存您的两个潜在值:amap和简单值 ( bool):type Value struct {    Children MapType    V        bool}type MapType map[int]*Valuevar m MapType这基本上是 user3591723 建议的,所以我不会进一步详细说明。2. 带着一棵树这是#1 的变体,但通过这种方式我们可以清楚地传达它是一棵树。实现层次结构的最简洁的方法是使用树,其中的节点可能如下所示:type KeyType inttype ValueType stringtype Node struct {    Children map[KeyType]*Node    Value    ValueType}这样做的好处是您可以选择值类型(这是bool您的情况,但您可以将其更改为任何类型 - 我用于string演示)。为了轻松构建/管理您的树,我们可以在我们的Node类型中添加一些方法:func (n *Node) Add(key KeyType, v ValueType) {    if n.Children == nil {        n.Children = map[KeyType]*Node{}    }    n.Children[key] = &Node{Value: v}}func (n *Node) Get(keys ...KeyType) *Node {    for _, key := range keys {        n = n.Children[key]    }    return n}func (n *Node) Set(v ValueType, keys ...KeyType) {    n = n.Get(keys...)    n.Value = v}并使用它:1. 构建一棵树,2. 查询一些值,3. 更改一个值:root := &Node{Value: "root"}root.Add(0, "first")root.Get(0).Add(9, "second")root.Get(0, 9).Add(3, "third")root.Get(0).Add(4, "fourth")fmt.Println(root)fmt.Println(root.Get(0, 9, 3))fmt.Println(root.Get(0, 4))root.Set("fourthMod", 0, 4)fmt.Println(root.Get(0, 4))输出(在Go Playground上试试):&{map[0:0x104382f0] root}&{map[] third}&{map[] fourth}&{map[] fourthMod}3. 带有递归类型定义这可能令人惊讶,但可以map使用递归定义在 Go 中定义具有无限或动态“深度”的类型:type X map[int]X这就是它所说的:它是一个map带有int键和与地图本身相同类型的值。这种递归类型的最大缺点是它不能在值类型中存储任何“有用”的数据。它只能存储是否存在与类似bool信息(booltype:true或false)相同的值的“事实” ,这在极少数情况下可能就足够了,但在大多数情况下就不够了。让我们看一个构建“树”的例子:var x Xx = map[int]X{}x[0] = map[int]X{}x[0][9] = map[int]X{}x[0][9][3] = map[int]X{}x[0][4] = map[int]X{}fmt.Println(x)输出:map[0:map[9:map[3:map[]] 4:map[]]]如果我们想测试是否存在基于一系列键的“值”,我们有 2 个选项:使用特殊v, ok := m[i]索引(它报告指定键的值是否存在),或者测试该值是否不存在nil,例如m[i] != nil。让我们看一些测试上面构建的地图的例子:var ok bool_, ok = x[0][9][3]fmt.Println("x[0][9][3] exists:", ok, "; alternative way:", x[0][9][3] != nil)_, ok = x[0][9][4]fmt.Println("x[0][9][4] exists:", ok, "; alternative way:", x[0][9][4] != nil)_, ok = x[0][4]fmt.Println("x[0][4] exists:", ok, "; alternative way:", x[0][4] != nil)_, ok = x[0][4][9][9][9]fmt.Println("x[0][4][9][9][9] exists:", ok, "; alternative way:", x[0][4][9][9][9] != nil)输出:x[0][9][3] exists: true ; alternative way: truex[0][9][4] exists: false ; alternative way: falsex[0][4] exists: true ; alternative way: truex[0][4][9][9][9] exists: false ; alternative way: false在Go Playground上试试这些。注意:即使x[0][4]是最后一个“叶子”,进一步索引x[0][4][9][9][9]也不会引起恐慌,因为nil可以索引映射并产生值类型的零值(nil如果值类型是映射类型)。

泛舟湖上清波郎朗

好吧,我玩这个有点乐趣。这是一个比我之前做的更好的实现:type mymap map[int]*myentrytype myentry struct {&nbsp; &nbsp; m mymap&nbsp; &nbsp; b bool}func (mm mymap) get(idx ...int) *myentry {&nbsp; &nbsp; if len(idx) == 0 {&nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; }&nbsp; &nbsp; entry, ok := mm[idx[0]]&nbsp; &nbsp; if !ok {&nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; } else if len(idx) == 1 {&nbsp; &nbsp; &nbsp; &nbsp; return entry&nbsp; &nbsp; }&nbsp; &nbsp; for i := 1; i < len(idx); i++ {&nbsp; &nbsp; &nbsp; &nbsp; if entry == nil || entry.m == nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; entry = entry.m[idx[i]]&nbsp; &nbsp; }&nbsp; &nbsp; return entry}func (mm mymap) setbool(v bool, idx ...int) {&nbsp; &nbsp; if len(idx) == 0 {&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }&nbsp; &nbsp; if mm[idx[0]] == nil {&nbsp; &nbsp; &nbsp; &nbsp; mm[idx[0]] = &myentry{m: make(mymap), b: false}&nbsp; &nbsp; } else if mm[idx[0]].m == nil {&nbsp; &nbsp; &nbsp; &nbsp; mm[idx[0]].m = make(mymap)&nbsp; &nbsp; }&nbsp; &nbsp; if len(idx) == 1 {&nbsp; &nbsp; &nbsp; &nbsp; mm[idx[0]].b = v&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }&nbsp; &nbsp; entry := mm[idx[0]]&nbsp; &nbsp; for i := 1; i < len(idx); i++ {&nbsp; &nbsp; &nbsp; &nbsp; if entry.m == nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; entry.m = make(mymap)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; entry.m[idx[i]] = &myentry{m: make(mymap), b: false}&nbsp; &nbsp; &nbsp; &nbsp; } else if entry.m[idx[i]] == nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; entry.m[idx[i]] = &myentry{m: make(mymap), b: false}&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; entry = entry.m[idx[i]]&nbsp; &nbsp; }&nbsp; &nbsp; entry.b = v}func (m mymap) getbool(idx ...int) bool {&nbsp; &nbsp; if val := m.get(idx...); val != nil {&nbsp; &nbsp; &nbsp; &nbsp; return val.b&nbsp; &nbsp; }&nbsp; &nbsp; return false}func (m mymap) getmap(idx ...int) mymap {&nbsp; &nbsp; if val := m.get(idx...); val != nil {&nbsp; &nbsp; &nbsp; &nbsp; return val.m&nbsp; &nbsp; }&nbsp; &nbsp; return nil}这样的事情应该让你开始

Smart猫小萌

如果您不需要分层映射结构并且只想使用可变长度的键,那么一种方法可能是简单地使用字符串作为键和一个单独的映射。m := make(map[string]bool)k := fmt.Sprintf("%v_%v_%v", 1, 2, 3)m[k] = truefmt.Println(m[k])
随时随地看视频慕课网APP

相关分类

Go
我要回答