我的自定义结构实现了Hashable
Protocol
。但是,当在键中插入键时发生哈希冲突时Dictionary
,不会自动处理它们。我该如何克服这个问题?
我之前曾问过这个问题,
如何在Swift中为Int数组(自定义字符串struct)实现哈希协议。后来我添加了自己的答案,似乎很有效。
但是,最近我hashValue
在使用时发现了一个细微的碰撞问题Dictionary
。
我已将代码简化为以下示例。
定制结构
struct MyStructure: Hashable {
var id: Int
init(id: Int) {
self.id = id
}
var hashValue: Int {
get {
// contrived to produce a hashValue collision for id=1 and id=2
if id == 1 {
return 2
}
return id
}
}
}
func ==(lhs: MyStructure, rhs: MyStructure) -> Bool {
return lhs.hashValue == rhs.hashValue
}
请注意,为了使等式运算符(==)重载,以使其符合Hashable协议所要求的Equatable协议,它具有全局功能。
微妙的字典关键问题
如果我创建一个Dictionary
with MyStructure
作为键
var dictionary = [MyStructure : String]()
let ok = MyStructure(id: 0) // hashValue = 0
let collision1 = MyStructure(id: 1) // hashValue = 2
let collision2 = MyStructure(id: 2) // hashValue = 2
dictionary[ok] = "some text"
dictionary[collision1] = "other text"
dictionary[collision2] = "more text"
print(dictionary) // [MyStructure(id: 2): more text, MyStructure(id: 0): some text]
print(dictionary.count) // 2
相等的哈希值会导致collision1
密钥被密钥覆盖collision2
。没有警告。如果这样的冲突在带有100个键的字典中仅发生一次,则很容易错过。(花了我一段时间才注意到这个问题。)
字典文字的明显问题
但是,如果我用字典文字重复此操作,则问题将变得更加明显,因为会引发致命错误。
let ok = MyStructure(id: 0) // hashValue = 0
let collision1 = MyStructure(id: 1) // hashValue = 2
let collision2 = MyStructure(id: 2) // hashValue = 2
let dictionaryLiteral = [
ok : "some text",
collision1 : "other text",
collision2 : "more text"
]
// fatal error: Dictionary literal contains duplicate keys
我的印象是,不必hashValue
总是返回唯一值。例如,马特·汤普森(Matt
Thompson)说,
关于实现自定义哈希函数的最常见误解之一来自……认为哈希值必须是不同的。
尊敬的SO用户@Gaffa说,处理哈希冲突的一种html" target="_blank">方法是
认为哈希码是非唯一的,并对实际数据使用相等比较器来确定唯一性。
我认为问题是快速可哈希协议哈希函数是否需要返回唯一值?在撰写本文时尚未得到足够的答复。
阅读完SwiftDictionary
问题后,如何处理哈希冲突?),我认为Swift会自动处理与的哈希冲突Dictionary
。但是显然,如果我使用的是自定义类或结构,那是不对的。
func ==(lhs: MyStructure, rhs: MyStructure) -> Bool {
return lhs.hashValue == rhs.hashValue
}
是否为每个字典键查找或仅在发生哈希冲突时才调用此函数?(更新:请参阅此问题)
当(且仅当)哈希冲突发生时,我该怎么做才能确定唯一性?
func ==(lhs: MyStructure, rhs: MyStructure) -> Bool {
return lhs.hashValue == rhs.hashValue
}
请注意,为了使等式运算符(==)重载,以使其符合Hashable协议所要求的Equatable协议,它的全局功能。
您的问题是不正确的 相等 实现。
哈希表(例如Swift字典或Set)需要单独的 相等 和 哈希 实现。
哈希 使您靠近要查找的对象; 平等为 您提供了您正在寻找的确切对象。
您的代码对 哈希 和 相等 使用相同的实现,这将确保发生冲突。
要解决此问题,请实现 相等性 以匹配确切的对象值(但是您的模型定义了相等性)。例如:
func ==(lhs: MyStructure, rhs: MyStructure) -> Bool {
return lhs.id == rhs.id
}
问题内容: 当大小超过maxthreshold值时,如何在哈希表或哈希表中进行重新哈希处理? 是否所有对都已复制到新的存储桶阵列中? 编辑: 重新哈希后,同一存储桶(位于链接列表中)中的元素会发生什么情况?我的意思是说,他们在重新哈希处理后会留在同一个桶中吗? 问题答案: 问题中的最大阈值称为负载系数。 建议负载系数约为0.75。负载因子定义为(m / n),其中n是哈希表的总大小,m是在需要增加
问题内容: 我正在开发一个Android应用程序,并且在发送到数据库之前有一些我想加密的字符串。我想要一个安全,易于实现的东西,每次传递相同的数据时都会生成相同的东西,并且无论传递给它的字符串有多大,最好都会使字符串保持恒定的长度。也许我正在寻找一个哈希。 问题答案: 此代码段为任何给定的字符串计算md5 资料来源:http : //www.androidsnippets.com/snippets
问题内容: 我想用JavaScript创建地图对象。我想到了以下想法: 但是我怎么才能找到一个特定的密钥是否存在? 问题答案: 如果要命名键,请不要使用数组,而应使用普通对象。 然后:
问题内容: 你们中 有谁 知道如何在 AngularJS中 很好地处理锚点哈希链接吗? 我为简单的常见问题解答页面添加了以下标记 单击上面的任何链接时,AngularJS会拦截并将我路由到一个完全不同的页面(在我的情况下是404页,因为没有路由与这些链接匹配。) 我的第一个想法是创建一个匹配“ / faq /:chapter ” 的路由,并在相应的控制器中检查匹配的元素之后,然后使用jQuery向
问题内容: 在Objective-C中,它看起来像这样: 我需要Swift这样的东西,可以吗? 请显示工作示例。 问题答案: 您的Objective-C代码(使用类别)可以直接转换为Swift(使用扩展名)。 首先,您必须创建一个“桥接头”并添加 然后: 这可以写得更短和更快速 Swift 2更新: 要返回以Base-64编码的字符串而不是十六进制编码的字符串,只需替换 与 Swift 3更新:
问题内容: 如何转义URL查询字符串中发送的哈希符号(有时称为数字符号或井号)? 问题答案: 百分比编码。将哈希替换为。