【问题标题】:Unique Hash from struct来自结构的唯一哈希
【发布时间】:2018-06-23 12:27:45
【问题描述】:

我想从一个结构数组中生成一个唯一的散列。顺序可能不同,但值相同。

例子:

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"} }}

在这两种情况下,哈希值应该相同,因为结构内的值是相同的。

编辑:基本上这个想法是为缓存生成一个唯一的哈希!我想组合每个结构的单独哈希!

【问题讨论】:

  • 地图在设计上是无序的。使用数组来保持顺序。
  • 不清楚你在问什么。你想散列结构的 slice (不是数组),还是散列单个结构?最好问问为什么。您要检查内容是否相等(无论顺序如何),还是要校验和?请澄清。
  • 基本上这个想法是为缓存生成一个唯一的哈希!我想组合每个结构的单独哈希!
  • 因此您需要包含无序数据结构的复杂数据结构的哈希值。实现这一点的最快方法是序列化您的数据(对字段进行排序)并使用足够大的东西对其进行哈希处理以避免冲突。但是,我严重怀疑您的缓存需要在整个数据上,它通​​常在一个非常有限的子集上(例如:有人查询唯一 ID 并获取大量数据。这意味着您的缓存键是唯一 ID,而不是数据)。

标签: go struct hash


【解决方案1】:

冯有一个观点,接受的答案不起作用不仅因为结构中没有导出字段,而且MD5哈希的方式确实具有顺序意义,见@ 987654321@.

不确定效果,但我可以通过使用 encoding/gobbytes 代表要在 Compare 中使用的哈希将切片作为字节传递来实现一些工作。

Playground

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】:

    也许https://github.com/mitchellh/hashstructure 可以帮助你。它始终对结构进行哈希处理,但可以与切片和数组一起使用。

    【讨论】:

    【解决方案3】:

    您可以通过将数组序列化为字节数组,然后计算字节数组的 md5 和来做到这一点。由于 md5 和是字节的散列 sum,因此顺序无关紧要。

    要序列化数组的每个元素,您可以使用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
    

    【讨论】:

    • 完美,我一直在寻找这个:“由于 md5 总和是字节的哈希总和,因此顺序无关紧要。”也许我需要开始阅读有关散列算法的更多信息:)
    • 因为SomeStruct中没有导出字段,所以marshal结果是一样的。如果将 param1 和 param1 更改为大写,哈希结果会有所不同。见play.golang.org/p/J9mJqSnCvDC
    • 如前所述,这个答案是完全错误的。为了使这样的事情起作用,数据需要以相同的顺序排列,因此您需要首先对结构进行排序。
    • 要增加这是多么错误,请在调试器中运行它并看到 jsonBytes == "{}"。您也可以只对jsonBytes 使用打印语句。 @MarcoTalento 请将此作为已接受的答案删除。
    • 任何人都可以确认 JSON 编组器/编码器是确定性的,即使在版本之间也是如此?甚至一年后,生成的哈希值是否相同(未来版本的 Go)?
    猜你喜欢
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-19
    • 2014-05-11
    • 2015-10-06
    • 1970-01-01
    相关资源
    最近更新 更多