簡體   English   中英

如何在go中為哈希映射制作復合鍵

[英]How to make composite key for a hash map in go

首先,我對復合鍵的定義 - 兩個或更多的值組合成鍵。 不要與數據庫中的復合鍵混淆。

我的目標是將pow(x, y)計算值保存在哈希表中,其中xy是整數。 這是我需要關於如何制作密鑰的想法的地方,以便給定xy ,我可以在哈希表中查找它,以找到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結構類型實現了這一點。

規范:比較運算符:如果所有字段都具有可比性,則結構值可比較。 如果相應的非空白字段相等,則兩個結構值相等。

一個重要的事情是:你不應該使用指針作為鍵類型(例如*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

總而言之,當您需要在同一個映射中保留兩組 K/V 對時,這可能是一種有趣的方法,例如保持函數簽名的某些完整性或避免定義具有 N 個非常相似的映射字段的結構。

游樂場https://play.golang.org/p/0t7fcvSWdy7

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM