首先,我的复合键定义是指两个或更多值组合成键。不要与数据库中的复合键混淆。
我的目标是在哈希表中保存计算出的 pow(x, y)
值,其中x
和y
是整数。这就是我需要想法来创建一个键,以便在给定x
和y
时,可以在哈希表中查找它,找到pow(x,y)
的地方。
例如:
pow(2, 3) => {key(2,3):8}
我想要弄清楚的是如何获得键为(2,3)
的映射表键,即生成一个由多个值组成的键,并在哈希表中使用它的最佳方法。
首先,我的复合键定义是指两个或更多值组合成键。不要与数据库中的复合键混淆。
我的目标是在哈希表中保存计算出的 pow(x, y)
值,其中x
和y
是整数。这就是我需要想法来创建一个键,以便在给定x
和y
时,可以在哈希表中查找它,找到pow(x,y)
的地方。
例如:
pow(2, 3) => {key(2,3):8}
我想要弄清楚的是如何获得键为(2,3)
的映射表键,即生成一个由多个值组成的键,并在哈希表中使用它的最佳方法。
最简单和最灵活的方法是使用 struct
作为键类型,其中包括您想要成为键的所有数据,在您的情况下:
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 ),因为比较指针仅比较内存地址,而不是指向的值。
还要注意,您也可以使用数组(而不是切片)作为键类型,但是数组不像结构体那样灵活。您可以在此处阅读更多信息:为什么要在Go中使用数组?
这是使用数组的样子:
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}])
输出结果相同。在Go Playground上尝试一下。
Go无法为int切片创建哈希。因此,我的方法是将一个结构映射到一个数字。
以下是如何实现的示例:
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])
}
其他答案已经很好地解决了您的具体问题。我想再添加一个额外的技巧,在某些特殊情况下可能会有用。
考虑到映射键必须是可比较的,您还可以使用接口。如果它们的动态值是可比较的,则接口是可比较的。
这使您可以基本上将映射分区,即在同一数据结构中使用多种类型的键。例如,如果您想在映射中存储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
type myKey struct {x,y int}; m := map[myKey]int{myKey{2,3}:8,};//...
- user4466350