使用集合对自定义对象去重问题

2,486 阅读2分钟

isEqual与==

    UIColor *color1 = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:1.0];
    UIColor *color2 = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:1.0];
    NSLog(@"color1 == color2 = %@", color1 == color2 ? @"YES" : @"NO");
    NSLog(@"[color1 isEqual:color2] = %@", [color1 isEqual:color2] ? @"YES" : @"NO");

color1 == color2 = NO
[color1 isEqual:color2] = YES

==只是简单的用来判断是否是一个对象;isEqual方法用来判断对象是否相同,例如UIColor对象表示的就是color是否相同

如何使用NSSet对系统对象进行去重(NSString、NSDictionary...)

    NSMutableSet *mutSet = [NSMutableSet set];
    [mutSet addObject:@"123"];
    [mutSet addObject:@"1234"];
    [mutSet addObject:@"123"];
    NSArray *array = mutSet.allObjects;
    NSLog(@"%@",array);

元素添加进集合的时候会根据hash值、进行isEqual判断对象是否相同,相同的不会再添加进集合。

如何使用NSSet对自定义对象进行去重

对自定义的对象去重,需要重新实现isEqual 和 hash方法,比如一个Person类只要uid相同就认为对象相同

- (BOOL)isEqual:(id)object {
    if (self == object) {
        return YES;
    }
    Person *otherPerson = (Person *)object;
    if (self.uid == otherPerson.uid) {
        return YES;
    }
    return NO;
}

- (NSUInteger)hash{
    return self.uid ^ self.name.hash;
}

装入NSSet后进行对象去重:

    Person *person1 = [Person new];
    person1.name = @"123";
    person1.uid = 1;
    
    Person *person2 = [Person new];
    person2.name = @"1234";
    person2.uid = 2;
    
    Person *person3 = [Person new];
    person3.name = @"345";
    person3.uid=  1;
    
    NSMutableSet *mutSet = [NSMutableSet set];
    [mutSet addObject:person1];
    [mutSet addObject:person2];
    [mutSet addObject:person3];
    
    NSArray *array = mutSet.allObjects;
    NSLog(@"%@",array);

打印结果:

    "0x60000160e220(2,1234)",
    "0x60000160e200(1,123)"

重写isEqual应该都理解,为什么要重写- (NSUInteger)hash方法?

先看一下如果不重写- (NSUInteger)hash

打印结果:

    "0x6000023d66c0(2,1234)",
    "0x6000023d61e0(1,345)",
    "0x6000023d6320(1,123)"

注意⚠️:一定要多试一下,这个是偶现。

为什么会这样呢?

其实吧NSMutableSet/NSSet,是一个无序集合容器,不像我们上面想的那么简单。
仅仅实现- (BOOL)isEqual:而不实现- (NSUInteger)hash没门。
NSMutableSet/NSSet在数据存储和比较元素相等都和- (NSUInteger)hash方法息息相关。
内部高效滤重机制有- (NSUInteger)hash的很大功劳。

为什么重写- (NSUInteger)hash,看到过好几篇文章意思大多是

当前成员的hash值是否和目标hash值相等, 如果相同进行isEqual判断, 如果不等, 直接判断不相等

但是我实际实验结果却是两个对象的hash值并不相等,但是却依旧进行isEqual判断,我得出的结论是:

isEqual的调用猜测应该是根据系统底层哈希表的实现来的。并不只是简单的根据hash值是否相等。

重写- (NSUInteger)hash:关键属性的hash进行一个简单的 XOR(异或)操作,就能够满足在 99% 的情况下的需求。

return self.uid ^ self.name.hash;

总结:

判断自定义对象的是否相同,

1.重写- (BOOL)isEqual:(id)object

2.重写- (NSUInteger)hash


参考:nshipster.cn/equality/

www.jianshu.com/p/915356e28…