为了账号安全,请及时绑定邮箱和手机立即绑定

如何在 go 中为哈希映射创建复合键

如何在 go 中为哈希映射创建复合键

Go
尚方宝剑之说 2023-04-04 15:09:11
首先,我对组合键的定义——两个或多个值组合起来构成键。不要与数据库中的复合键混淆。我的目标是将 的计算值保存pow(x, y)在哈希表中,其中x和y是整数。这是我需要关于如何制作密钥的想法的地方,以便给定x和y,我可以在哈希表中查找它,找到pow(x,y).例如:pow(2, 3) => {key(2,3):8}我想弄清楚的是如何获取 pair 的映射键(2,3),即生成一个键的最佳方法,该键是多个值的组合,并在哈希表中使用它。
查看完整描述

3 回答

?
慕村9548890

TA贡献1884条经验 获得超4个赞

最简单和最灵活的方法是使用 astruct作为键类型,包括您希望成为键一部分的所有数据,因此在您的情况下:


type Key struct {

    X, Y int

}

就这样。使用它:


m := map[Key]int{}

m[Key{2, 2}] = 4

m[Key{2, 3}] = 8


fmt.Println("2^2 = ", m[Key{2, 2}])

fmt.Println("2^3 = ", m[Key{2, 3}])

输出(在Go Playground上尝试):

2^2 =  4
2^3 =  8

规范:映射类型:您可以使用任何类型作为比较运算符==!=完全定义的键,上面的Key结构类型实现了这一点。

规范:比较运算符:如果结构值的所有字段都是可比较的,则结构值是可比较的。如果两个结构值对应的非空白字段相等,则它们相等。

一件重要的事情:你不应该使用指针作为键类型(例如*Key),因为比较指针只比较内存地址,而不是指向的值。

另请注意,您也可以使用数组(不是slices)作为键类型,但数组不如结构灵活。您可以在此处阅读

这就是数组的样子:

type Key [2]int


m := map[Key]int{}

m[Key{2, 2}] = 4

m[Key{2, 3}] = 8


fmt.Println("2^2 = ", m[Key{2, 2}])

fmt.Println("2^3 = ", m[Key{2, 3}])

输出是一样的。



查看完整回答
反对 回复 2023-04-04
?
宝慕林4294392

TA贡献2021条经验 获得超8个赞

Go 无法对一片整数进行散列。


因此,我采用的方法是将结构映射到数字。


这是一个如何做到这一点的例子:


package main


import (

    "fmt"

)


type Nums struct {

    num1 int

    num2 int

}


func main() {

    powers := make(map[Nums]int)

    numbers := Nums{num1: 2, num2: 4}


    powers[numbers] = 6


    fmt.Printf("%v", powers[input])

}

我希望这有帮助


查看完整回答
反对 回复 2023-04-04
?
侃侃尔雅

TA贡献1801条经验 获得超15个赞

其他答案很好地解决了您的具体问题。我想添加一个在某些极端情况下可能有用的额外技巧。


鉴于映射键必须是可比较的,您还可以使用接口。如果接口的动态值是可比较的,则接口是可比较的。


这允许您从本质上对映射进行分区,即在同一数据结构中使用多种类型的键。例如,如果您想在地图中存储 n 元组(它不适用于数组,因为数组长度是类型的一部分)。


这个想法是用一个虚拟方法定义一个接口(但它肯定不是虚拟的),并将其用作映射键:


type CompKey interface {

    isCompositeKey() bool

}


var m map[CompKey]string

此时,您可以让任意类型实现接口,无论是显式实现还是仅通过嵌入实现。


在这个例子中,想法是使接口方法不被导出,这样其他结构就可以嵌入接口而不必提供实际的实现——不能从其包外部调用该方法。它只会发出该结构可用作复合映射键的信号。


type AbsoluteCoords struct {

    CompKey

    x, y int

}


type RelativeCoords struct {

    CompKey

    x, y int

}


func foo() {

    p := AbsoluteCoords{x: 1, y: 2}

    r := RelativeCoords{x: 10, y: 20}


    m[p] = "foo"

    m[r] = "bar"


    fmt.Println(m[AbsoluteCoords{x: 10, y: 20}]) // "" (empty, types don't match)

    

    fmt.Println(m[RelativeCoords{x: 10, y: 20}]) // "bar" (matches, key present)

}

当然,没有什么能阻止您在界面上声明实际的方法,这在遍历地图键时可能很有用。


这个接口键的缺点是现在你有责任确保实现类型实际上是可比较的。例如这个地图键会恐慌:


type BadKey struct {

    CompKey

    nonComparableSliceField []int

}


b := BadKey{nil, []int{1,2}}

m[b] = "bad!" // panic: runtime error: hash of unhashable type main.BadKey

总而言之,当您需要在同一映射中保留两组 K/V 对时,这可能是一种有趣的方法,例如,为了保持函数签名的完整性或避免定义具有 N 个非常相似的映射字段的结构。


查看完整回答
反对 回复 2023-04-04
  • 3 回答
  • 0 关注
  • 136 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信