我正在制作一个类似于的结构String
,只是它只处理UnicodeUTF-32标量值。因此,它是的数组UInt32
。
我希望能够将自定义ScalarString
结构用作字典中的键。例如:
var suffixDictionary = [ScalarString: ScalarString]() // Unicode key, rendered glyph value
// populate dictionary
suffixDictionary[keyScalarString] = valueScalarString
// ...
// check if dictionary contains Unicode scalar string key
if let renderedSuffix = suffixDictionary[unicodeScalarString] {
// do something with value
}
为了做到这一点,ScalarString
需要实现Hashable
Protocol
。我以为我可以做这样的事情:
struct ScalarString: Hashable {
private var scalarArray: [UInt32] = []
var hashValue : Int {
get {
return self.scalarArray.hashValue // error
}
}
}
func ==(left: ScalarString, right: ScalarString) -> Bool {
return left.hashValue == right.hashValue
}
但是后来我发现Swift数组没有hashValue
。
文章在斯威夫特实施哈希的协议策略有很多伟大的想法,但我没有看到任何这似乎是他们会在这种情况下很好地工作。特别,
hashValue
)这是我阅读的其他内容:
Swift字符串具有一个hashValue
属性,因此我知道可以做到。
如何hashValue
为自定义结构创建一个?
更新1:
我想做一些不涉及转换为String
,然后使用String
的的事情hashValue
。建立我自己的结构的全部目的是为了避免进行大量String
转换。从某个地方String
得到它hashValue
。看来我可以使用相同的方法来获得它。
更新2: 我一直在研究其他上下文中字符串哈希码算法的实现。不过,我很难知道哪种方法最好,并在Swift中进行表达。
hashCode
算法更新3
我宁愿不导入任何外部框架,除非这是进行这些操作的推荐方法。
我使用DJB哈希函数提交了可能的解决方案。
马丁·R 写道:
从 Swift 4.1开始 , 如果所有成员都符合Equatable /
Hashable(SE0185),则编译器可以自动进行合成Equatable
并Hashable
实现类型一致性。从 Swift 4.2开始
,Swift标准库(SE-0206)中内置了一个高质量的哈希组合器。因此,不再需要定义自己的哈希函数,只需声明一致性即可:
struct ScalarString: Hashable, ... { private var scalarArray: [UInt32] = [] // ... }
因此,下面的答案需要重写(再次)。 在此之前,请从上面的链接中参考Martin R的答案。
将我的原始答案提交给代码审查后,该答案已被完全重写。
该哈希的协议允许您使用您的自定义类或结构作为字典键。为了实施此协议,您需要
hashValue
这些要点来自文档中给出的公理:
x == y
暗示x.hashValue == y.hashValue
其中x
和y
是某种类型的值。
为了实现Equatable协议,您可以定义类型如何使用==
(等效)运算符。在您的示例中,等效性可以这样确定:
func ==(left: ScalarString, right: ScalarString) -> Bool {
return left.scalarArray == right.scalarArray
}
该==
函数是全局函数,因此它超出了您的类或结构。
hashValue
您的自定义类或结构还必须具有一个计算hashValue
变量。一个好的哈希算法将提供广泛的哈希值。但是,应注意,您不必保证哈希值都是唯一的。当两个不同的值具有相同的哈希值时,这称为哈希冲突。发生冲突时,这需要一些额外的工作(这就是为什么需要良好的分布)的原因,但是某些冲突是可以预期的。据我了解,该==
功能可以完成额外的工作。(
有多种计算哈希值的方法。例如,您可以做一些简单的事情,就像返回数组中的元素数一样。
var hashValue: Int {
return self.scalarArray.count
}
每当两个数组具有相同数量的元素但值不同时,就会产生哈希冲突。NSArray
显然使用这种方法。
DJB哈希函数
DJB哈希函数是与字符串一起使用的常见哈希函数。这是我将要使用的那个,但是在这里请查看其他一些。
@MartinR提供的 Swift实现如下:
var hashValue: Int {
return self.scalarArray.reduce(5381) {
($0 << 5) &+ $0 &+ Int($1)
}
}
这是我原始实现的改进版本,但让我也包括了较旧的扩展格式,对于不熟悉的人来说,它可能更易读reduce
。我认为这是等效的:
var hashValue: Int {
// DJB Hash Function
var hash = 5381
for(var i = 0; i < self.scalarArray.count; i++)
{
hash = ((hash << 5) &+ hash) &+ Int(self.scalarArray[i])
}
return hash
}
该&+
运营商允许Int
溢出和长串重新开始。
我们已经研究了各个部分,但现在让我展示与哈希协议相关的整个示例代码。ScalarString
是问题中的自定义类型。当然,这对于不同的人来说是不同的。
// Include the Hashable keyword after the class/struct name
struct ScalarString: Hashable {
private var scalarArray: [UInt32] = []
// required var for the Hashable protocol
var hashValue: Int {
// DJB hash function
return self.scalarArray.reduce(5381) {
($0 << 5) &+ $0 &+ Int($1)
}
}
}
// required function for the Equatable protocol, which Hashable inheirits from
func ==(left: ScalarString, right: ScalarString) -> Bool {
return left.scalarArray == right.scalarArray
}
非常感谢CodeReview中的MartinR。我的改写主要是基于他的回答。如果您觉得这有帮助,请给他点赞。
Swift现在是开源的,因此可以从源代码中了解如何hashValue
实现。它似乎比我在这里给出的答案更复杂,并且我还没有花时间对它进行全面分析。自己动手做。String
问题内容: 如何转义URL查询字符串中发送的哈希符号(有时称为数字符号或井号)? 问题答案: 百分比编码。将哈希替换为。
问题内容: 例如: 有任何内置功能可以做到这一点吗? 谢谢。 问题答案: 该散包是这很有帮助。请注意,这是对特定哈希实现的抽象。在软件包子目录中可以找到一些现成的。 例: (也在这里) 输出:
我目前有一个自定义对象数组 [基因报告员] 定义如下: 当打印到console时,它如下所示: [MyMovieGuide.GenrePosters(海报:/e1mjopzAS2KNsvpbpahQ1a6SkSn.jpg),MyMovieGuide.GenrePosters(海报:/jjbgi2r5crt36xf6inuehzsceb.jpg),MyMovieGuide.GenrePosters(
Kotlin有许多速记和有趣的特性。所以,我想知道是否有一些快捷的方法可以将字符串数组转换为整数数组。与Python中的此代码类似:
问题内容: 我需要定义一个数组,其中包含所有以下特殊字符。 我正在用这个 它接受除“和\以外的所有字符 请帮助如何定义这两个。 问题答案: 并且是String类中的特殊字符 是String的开始或结尾 用于创建如新线的某些字符 标签或你的情况逃脱特殊字符,如和 因此,要使它们成为文字,您必须使用和 另一个想法是使用而不是,这样您就不必转义,并且您的字符可以写为或(因为要求转义- 应该写为- 在这里
问题内容: 我有一个要哈希的字符串。在node.js中生成哈希的最简单方法是什么? 哈希用于版本控制,而非安全性。 问题答案: 看看crypto.createHash(algorithm)