Me gustaría generar un hash único a partir de una matriz de estructuras. El orden puede ser diferente pero los valores son los mismos.
Ejemplo:
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"} }}
En ambos casos, el hash debe ser el mismo ya que los valores dentro de las estructuras son los mismos.
EDITAR: ¡Básicamente, la idea es generar un hash único para el almacenamiento en caché! ¡Quiero combinar el hash individual de cada estructura!
3 respuestas
Puede hacer esto serializando la matriz a una matriz de bytes, luego calculando la suma md5 de la matriz de bytes. Dado que la suma md5 es la suma hash de los bytes, el orden no importará.
Para serializar cada elemento de la matriz, puede usar json.Marshal
, que funcionará para cualquier tipo de struct
.
La función hash se verá más o menos así:
func Hash(arr []SomeStruct) [16]byte {
arrBytes := []byte{}
for _, item := range arr {
jsonBytes, _ := json.Marshal(item)
arrBytes = append(arrBytes, jsonBytes...)
}
return md5.Sum(arrBytes)
}
Puede ejecutar el programa de ejemplo de trabajo aquí
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)
}
Lo que dará salida:
Hash1: d065fee603fdcf75115204ec65310e1c
Hash2: d065fee603fdcf75115204ec65310e1c
Quizás https://github.com/mitchellh/hashstructure podría ayudarlo. Constantemente hashes estructura pero se puede utilizar con sectores y matrices.
Feng tiene un punto, la respuesta aceptada no funciona no solo porque no hay campos exportados en la estructura, sino también por el hecho de que el hash MD5 sí tiene importancia para el orden, vea RFC 1321 3.4.
No estoy seguro de la eficacia, pero tengo algo que funciona al pasar el segmento como bytes usando encoding/gob
y bytes
que representa un hash para usar en 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()
}
Preguntas relacionadas
Nuevas preguntas
go
Go es un lenguaje de programación de código abierto. Está tipado estáticamente, con una sintaxis derivada libremente de C, que agrega administración de memoria automática, seguridad de escritura, algunas capacidades de tipeo dinámico, tipos incorporados adicionales, como matrices de longitud variable (llamados cortes) y mapas de valores clave, y un Gran biblioteca estándar.