我想从结构数组中生成一个唯一的哈希。订单可能不同,但值相同。
示例:
type MyStruct struct {
ID string
Parameters map[string]interface{}
}
arr:= []MyStruct{MyStruct{ID: "test", Parameters: map[string]interface{}{"key": true, "key2": "value"} }, MyStruct{ID: "test2", Parameters: map[string]interface{}{"key2": "value", "key": true} }}
//The order is different even inside the Parameters fields
arr:= []MyStruct{MyStruct{ID: "test2", Parameters: map[string]interface{}{"key2": "value", "key": true} },MyStruct{ID: "test", Parameters: map[string]interface{}{"key": true, "key2": "value"} }}
在这两种情况下,哈希应该是相同的,因为结构内部的值是相同的。
编辑:基本上我的想法是为缓存生成一个唯一的哈希!我想结合每个结构的单个哈希值!
答案 0 :(得分:2)
您可以通过将数组序列化为字节数组,然后计算字节数组的md5总和来完成此操作。由于md5和是字节的散列和,因此顺序无关紧要。
要序列化数组的每个元素,您可以使用json.Marshal
,它适用于任何类型的struct
。
哈希函数看起来像这样:
func Hash(arr []SomeStruct) [16]byte {
arrBytes := []byte{}
for _, item := range arr {
jsonBytes, _ := json.Marshal(item)
arrBytes = append(arrBytes, jsonBytes...)
}
return md5.Sum(arrBytes)
}
您可以运行工作示例程序here
func main() {
arr1 := []SomeStruct{
{
param1: "abc",
param2: 3,
},
{
param1: "def",
param2: 5,
}, {
param1: "deg",
param2: 0,
},
}
arr2 := []SomeStruct{
{
param1: "deg",
param2: 0,
},
{
param1: "def",
param2: 5,
},
{
param1: "abc",
param2: 3,
},
}
fmt.Printf("Hash1: %x\n", Hash(arr1))
fmt.Printf("Hash2: %x\n", Hash(arr2))
}
func Hash(arr []SomeStruct) [16]byte {
arrBytes := []byte{}
for _, item := range arr {
jsonBytes, _ := json.Marshal(item)
arrBytes = append(arrBytes, jsonBytes...)
}
return md5.Sum(arrBytes)
}
将输出:
Hash1: d065fee603fdcf75115204ec65310e1c
Hash2: d065fee603fdcf75115204ec65310e1c
答案 1 :(得分:2)
Feng有一点,接受的答案不起作用,不仅因为结构中没有导出的字段,而且还因为MD5哈希确实具有顺序意义的事实,请参见{ {3}}。
不确定效率,但是通过使用encoding/gob
和bytes
表示要在Compare
中使用的哈希值作为字节传递切片,我可以起到一些作用。
package main
import (
"bytes"
"encoding/gob"
"fmt"
)
type S struct {
K1 string
K2 int
}
func main() {
sa := []S{{ K1: "foo", K2: 1}, {K1: "bar", K2: 2}, {K1: "baz", K2: 3,}}
sb := []S{{ K1: "baz", K2: 3}, {K1: "bar", K2: 2}, {K1: "foo", K2: 1,}}
sc := []S{}
a := Hash(sa)
b := Hash(sb)
c := Hash(sc)
fmt.Println(Compare(a, b))
fmt.Println(Compare(a, c))
}
func Compare(a, b []byte) bool {
a = append(a, b...)
c := 0
for _, x := range a {
c ^= int(x)
}
return c == 0
}
func Hash(s []S) []byte {
var b bytes.Buffer
gob.NewEncoder(&b).Encode(s)
return b.Bytes()
}
答案 2 :(得分:1)
也许https://github.com/mitchellh/hashstructure可以为您提供帮助。它始终对结构进行散列处理,但可以与切片和数组一起使用。