实现-hash / -isEqual:/ - isEqualTo ...:用于Objective-C集合

时间:2009-07-10 22:59:27

标签: objective-c cocoa data-structures equality chdatastructures

3 个答案:

答案 0 :(得分:18)

我认为尝试提出一些通常有用的哈希函数,它将为集合生成唯一的哈希值,这是徒劳的。 U62关于组合所有内容的散列的建议将不能很好地扩展,因为它使散列函数O(n)。散列函数应该确实是O(1)以确保良好的性能,否则散列的目的就会失败。 (考虑一下plists的常见Cocoa构造,它是包含数组和其他字典的字典,可能是令人作呕的。如果集合的散列函数是O(如果集合的散列函数是O),尝试获取大plist的顶级字典的散列将会非常慢。 n)中。)

我的建议是不要担心收藏品的散列问题。如您所述,-isEqual:意味着相等的-hash值。另一方面,相等的-hash暗示-isEqual:。这个事实为你创造一个简单的哈希提供了很大的余地。

如果您真的担心碰撞(并且您在实际情况的具体测量中有证据确认它是值得担心的事情),您仍然可以遵循U62的建议一定程度上。例如,您可以获取集合中第一个和/或最后一个元素的哈希值,并将其与集合的-count组合。这足以提供一个像样的哈希。

我希望至少回答你的一个问题。

至于第1号:实施-isEqual:非常简单和干燥。您枚举内容,并在每个元素上检查isEqual:

有一点需要注意,这可能会影响您决定为集合的-hash功能做些什么。您的馆藏客户还必须了解管理-isEqual:-hash的规则。如果您使用收藏集-hash中的内容“-hash,那么如果内容”isEqual:-hash不同意,您的收藏就会中断。当然,这是客户的错,但这是另一个反对将-hash基于集合内容的论据。

没有。 2有点模糊。不知道你有什么想法。

答案 1 :(得分:4)

如果两个集合包含相同的元素,则应视为相等;如果集合是有序的,则两个集合应视为相同的顺序。

关于集合的散列的主题,它应该足以以某种方式组合元素的散列(对它们进行异或或以模数添加它们)。请注意,虽然规则声明两个根据IsEqual相等的对象需要返回相同的哈希,但相反的情况并不成立:尽管哈希的唯一性是可取的,但对于解的正确性并不是必需的。因此,有序集合不需要考虑元素的顺序。

顺便提一下Apple文档的摘录是一个必要的限制。对象无法在突变下维护相同的哈希值,同时还要确保具有相同值的对象具有相同的哈希值。这适用于最简单的对象和集合。当然,通常只有当对象的哈希在使用哈希来组织它的元素的容器内时才会发生变化。所有这一切的结果是,当置于另一个容器中时,可变集合不应该变异,但是任何具有真正散列函数的对象都不应该变异。

答案 2 :(得分:3)

我已经对NSArray和NSMutableArray默认哈希实现进行了一些调查,并且(除非我误解了某些内容)它像Apple这样的接缝不遵循自己的规则:

  

如果将可变对象添加到使用哈希值的集合中   确定对象在集合中的位置,返回值   通过对象的哈希方法,对象不能更改   在集合中。因此,要么哈希方法不能依赖   任何对象的内部状态信息或您必须确保   对象的内部状态信息不会改变   对象在集合中。因此,例如,可变字典   可以放在哈希表中,但是当它进入时你不能改变它   那里。 (注意,可能很难知道是否给定   对象在集合中。)

这是我的测试代码

NSMutableArray* myMutableArray = [NSMutableArray arrayWithObjects:@"a", @"b", @"c", nil];
NSMutableArray* containerForMutableArray = [NSMutableArray arrayWithObject:myMutableArray];

NSUInteger hashBeforeMutation = [[containerForMutableArray objectAtIndex:0] hash];
[[containerForMutableArray objectAtIndex:0] removeObjectAtIndex:1];
NSUInteger hashAfterMutation = [[containerForMutableArray objectAtIndex:0] hash];

NSLog(@"Hash Before: %d", hashBeforeMutation);
NSLog(@"Hash After : %d", hashAfterMutation);

输出结果为:

Hash Before: 3
Hash After : 2

因此,它接口就像NSArray和NSMutableArray上的Hash方法的默认实现一样,是数组的计数,它不在乎它是否在集合内部。