对象包含三个双精度值。如果所有三个值在任何可能的组合中相等,则两个对象相等。需要一个函数来确定数组中“唯一”对象的数量。 我想从数组生成Set并返回计数,但是符合Hashable协议需要hashValue函数... 在Swift上编码但在任何语言(外星人除外)上的算法将不胜感激:)
所以我需要三个双精度的hashValue(值的顺序无关紧要)或确定数组中唯一对象的任何其他解决方案
更新:“唯一”表示不相等。如上所述,两个具有双重值的对象(例如a,b,c)等于任何可能组合中的所有三个值。例如:
obj1 = (a: 1, b: 2, c: 3)
obj2 = (a: 3, b: 2, c: 1)
// obj1 is equal obj2
答案 0 :(得分:4)
这是一个让一个类保持3个双打Hashable
的示例,以便您可以使用Set
来确定数组中保存的唯一数量:
class Triple: Hashable {
var a: Double
var b: Double
var c: Double
// hashValue need only be the same for "equal" instances of the class,
// so the hashValue of the smallest property will suffice
var hashValue: Int {
return min(a, b, c).hashValue
}
init(a: Double, b: Double, c: Double) {
self.a = a
self.b = b
self.c = c
}
}
// Protocol Hashable includes Equatable, so implement == for type Triple:
// Compare sorted values to determine equality
func ==(lhs: Triple, rhs: Triple) -> Bool {
return [lhs.a, lhs.b, lhs.c].sorted() == [rhs.a, rhs.b, rhs.c].sorted()
}
let t1 = Triple(a: 3, b: 2, c: 1)
let t2 = Triple(a: 1, b: 2, c: 3)
let t3 = Triple(a: 1, b: 3, c: 2)
let t4 = Triple(a: 3, b: 3, c: 2)
let arr = [t1, t2, t3, t4]
// Find out how many unique Triples are in the array:
let set = Set(arr)
print(set.count) // 2
讨论:更好的散列函数
正如@PatriciaShanahan在评论中指出的那样,在min
的计算中使用hashValue
有一些缺点:
min
因为涉及比较而价格昂贵。hashValue
的{{1}}时,仅考虑最小项目将导致许多具有相同Triple
的“常见”Triple
。例如,值hashValue
且两个正值的任何Triple
都具有相同的0
。我之所以选择hashValue
,是因为我觉得很容易理解,min
会为min(a, b, c)
,a
和{{的所有排序带来相同的价值1}}这意味着我们会为所有排序获得相同的b
。这很重要,因为我们认为c
s与3个值的排序无关,hashValue
对于值的任何排序必须相同,因为Triple
暗示{ {1}}。
我考虑过其他散列函数,例如:
hashValue
a == b
但这些都是有缺陷的。从数学上讲,加法和乘法是可交换的,因此从理论上讲,无论a.hashValue == b.hashValue
,(a + b + c).hashValue
和(a * b * c).hashValue
的顺序如何,这些都会产生相同的hashValue
。但是,实际上,更改操作顺序可能会导致溢出或下溢。
考虑以下示例:
a
类b
的理想散列函数将:
c
,let a = Int.max
let b = Int.min
let c = 5
let t1 = (a + b) + c // 4
let t2 = (a + c) + b // Overflow!
和Triple
的所有排序保证相同hashValue
。a
,b
或c
中的任何一项发生变化,则会更改结果。组合数字的一个好的数学运算是按位OR 函数a
。它通过比较两个值按位并将结果位设置为b
(如果两个位相同)和c
(如果位不同)组合两个值。
^
将其扩展为3个值:
0
如上表所示,所有订单均为1
,所有订单均为 a b result
--- --- ------
0 0 0
0 1 1
1 0 1
1 1 0
,所有订单均为 a b c result
--- --- --- ------
0 0 0 0
0 0 1 1
0 1 0 1
0 1 1 0
1 0 0 1
1 0 1 0
1 1 0 0
1 1 1 1
,所有订单均为XOR(0, 0, 0) = 0
。因此,使用异或来组合这些值符合为所有排序提供相同结果的第一个标准。
异或是一种快速操作。它由单个汇编指令实现。所以它符合良好散列函数的第二个标准。
如果XOR(1, 0, 0) = 1
,XOR(1, 1, 0) = 0
或XOR(1, 1, 1) = 1
中的任何一项发生变化,则a
的结果会发生变化。所以异或符合良好散列函数的第三个标准。
异或不能上溢或下溢,因为它只是设置位。因此它符合良好散列函数的第四个标准。
因此,更好的b
函数将是:
c