【iOS】Foundation 集合

NSSet集合类似一个罐子,把对象“丢进”NSSet集合,集合里多个对象之间没有明显的顺序NSSet不允许包含相同的元素, 如果试图把两个相同的元素放在同一个NSSet集合中,则只会保留一个元素。

NSSet的功能与用法

NSSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。

NSSet不能保证元素的添加顺序,顺序有可能发生变化。与NSArray相比,NSSet最大的区别是元素没有索引,因此不能根据索引来操作元素。

实际上,NSArray与NSSet依然有大量的相似之处,NSSet与NSArray在如下方面的调用机制都非常相似:

  • 都可以通过count方法获取集合元素的数量
  • 都可通过快速枚举来遍历集合元素。
  • 都可通过objectEnumerator方法获取NSEnumerator枚举器对集合元素进行遍历。
  • 都提供了makeObjectPerformSelector、makeObjectsPerformSelector:withObject:方法对集合元素整体调用某个方法,以及enumerateObjectsUsingBlock:、enumerateObjectsWithOptions:usingBlock:对集合整体或部分元素迭代执行代码块。
  • 都提供了valueForKey:和setValue:forKey:方法对集合元素整体进行KVC编程。
  • 都提供了集合的所有元素和部分元素进行KVO编程的方法。

NSSet代表集合元素无索引且不允许重复的集合;而NSArray则代表集合元素有索引且允许重复的集合。因此,可认为NSSet代表通用的集合,而NSArray则在NSSet基础上扩展了功能:主要是让集合有索引,因此,NSArray允许通过索引来操作集合元素。

NSSet同样提供了类方法和实例方法来创建NSSet,只是类方法以set开头,而实例方法则以init开头。

下面示例示范了NSSet集合的基本用法

#import <Foundation/Foundation.h>
//定义一个函数,该函数可把NSAarray或NSSet集合转换为字符串
NSString* NSCollectionToString(id collection) {
    
    
    NSMutableString* result = [NSMutableString stringWithString:@"["];
    //使用快速枚举遍历NSSet集合
    for(id obj in collection) {
    
    
        [result appendString:[obj description]];
        [result appendString:@", "];
    }
    //获取字符串长度
    NSUInteger len = [result length];
    //去掉字符串最后的两个字符
    [result deleteCharactersInRange:NSMakeRange(len - 2 , 2)];
    [result appendString:@"]"];
    return result;
}
int main(int argc, const char * argv[]) {
    
    
    @autoreleasepool {
    
    
        //用四个元素初始化NSSet集合
        //故意传入两个相等的元素,NSSet集合只会保留一个元素
        NSSet* set1 = [NSSet setWithObjects:@"疯狂iOS讲义" , @"疯狂Android讲义",
                       @"疯狂Ajax讲义" , @"疯狂iOS讲义" , nil];
        //程序输出set1集合中元素个数为3
        NSLog(@"set1集合中元素个数为%ld" , [set1 count]);
        NSLog(@"set1集合为:%@" , NSCollectionToString(set1));
        NSSet* set2 = [NSSet setWithObjects:@"孙悟空", @"疯狂Android讲义" , @"猪八戒" , nil];
        NSLog(@"set2集合:%@" , NSCollectionToString(set2));
        //向set1集合中添加单个元素,将添加元素后生成的新集合赋给set1
        set1 = [set1 setByAddingObject:@"疯狂Swift讲义"];
        NSLog(@"添加一个元素后:%@" , NSCollectionToString(set1));
        //使用NSSet集合向set1集合中添加多个元素,相当于计算两个集合的并集
        NSSet* s = [set1 setByAddingObjectsFromSet:set2];
        NSLog(@"set1和set2的并集:%@" , NSCollectionToString(s));
        BOOL b = [set1 intersectsSet:set2];
        NSLog(@"set1和set2是否有交集:%d" , b);
        BOOL bo = [set2 isSubsetOfSet:set1];
        NSLog(@"set2是否为set1的子集:%d" , bo);
        //判断NSSet集合是否包含指定元素
        BOOL bb = [set1 containsObject:@"疯狂Ajax讲义"];
        NSLog(@"set1是否包含\"疯狂iOS讲义\":%d" , bb);
        //下面两行代码将取出相同的元素,但取出哪个元素是不确定的
        NSLog(@"set1取出一个元素:%@" , [set1 anyObject]);
        NSLog(@"set2取出一个元素:%@" , [set1 anyObject]);
        //使用代码块对集合元素进行过滤
        NSSet* filteredSet = [set1 objectsPassingTest:^(id obj , BOOL *stop)
                              {
    
    
                                  return (BOOL)([obj length] > 8);
                              }];
        NSLog(@"set1中的元素的长度大于8的集合元素有:%@" , NSCollectionToString(filteredSet));
    }
    return 0;
}

效果:
在这里插入图片描述

NSSet判断集合元素重复的标准

//FKUser.h
#import <Foundation/Foundation.h>

@interface FKUser : NSObject
@property (nonatomic , copy) NSString* name;
- (id) initWithName: (NSString*)aName;
- (void) say:(NSString*) content;
@end
//FKUser.m
#import "FKUser.h"

@implementation FKUser
- (id) initWithName:(NSString *) aName {
    
    
    if (self = [super init]) {
    
    
        self.name = aName;
    }
    return self;
}

- (BOOL) isEqual:(id)other
{
    
    
    if (self == other) {
    
    
        return YES;
    }
    if ([other class] == FKUser.class) {
    
    
        FKUser* target = (FKUser*)other;
        return [self.name isEqualToString:target.name];
    }
    return NO;
}

- (id) description {
    
    
    return self.name;
}
- (void) say:(NSString *)content {
    
    
    NSLog(@"%@说:%@" , self.name , content);
}
@end

//main.m
#import <Foundation/Foundation.h>
#import "FKUser.h"

NSString* NSCollectionToString(id collection) {
    
    
    NSMutableString* result = [NSMutableString stringWithString:@"["];
    //使用快速枚举遍历NSSet集合
    for(id obj in collection) {
    
    
        [result appendString:[obj description]];
        [result appendString:@", "];
    }
    //获取字符串长度
    NSUInteger len = [result length];
    //去掉字符串最后的两个字符
    [result deleteCharactersInRange:NSMakeRange(len - 2 , 2)];
    [result appendString:@"]"];
    return result;
}
int main(int argc, const char * argv[]) {
    
    
    @autoreleasepool {
    
    
        NSSet* set = [NSSet setWithObjects:
                      [[FKUser alloc] initWithName:@"sun"],
                      [[FKUser alloc] initWithName:@"bai"],
                      [[FKUser alloc] initWithName:@"sun"],
                      [[FKUser alloc] initWithName:@"niu"],nil];
        NSLog(@"set集合元素的z个数为:%ld" , [set count]);
        NSLog(@"%@" , NSCollectionToString(set));
        
        //由于没重写hash方法,所有即使name的值相同,由于hashcode不同,系统还是会把它们当作两个元素
/*
    一、重写hash方法的基本规则:
            1、在程序运行过程中,同一个对象多次调用hash方法应该返回相同的值
            2、当两个对象通过isEqual:方法比较返回YES时,这两个对象的hash方法应返回相等的值
            3、对象中作为isEqual:方法比较标准的成员变量,都应该用来计算hashCode值
    二、重写hash的一般步骤:
            1、把对象内每个有意义的成员变量(即每个用作isEqual:方法比较标准的实例变量)计算出一个int类型的hashCode值。
            2、用第一步计算出来的多个hashCode值组合计算出一个hashCode值返回。例如:如下代码
                        return [f1 hash] + [f2 hash];
            注:
                为了避免直接相加产生偶然相等,可以通过为各实例变量的hashCode值乘以任意一个质数g后再相加。例如:
                        return [f1 hash] * 31 + [f2 hash];
 
*/
    }
    return 0;
}

效果:
在这里插入图片描述

所以需要重写hash方法,为FKUse类重写 hash方法:

- (NSUInteger) hash
{
    
    
    NSLog(@"===hash===");
    NSUInteger nameHash = self.name == nil ? 0 : [self.name hash];
    return nameHash;
}

效果:
在这里插入图片描述

NSMutableSet的功能与用法

NSMutableSet继承了NSSet,它代表一个集合元素可变的NSSet集合。由于NSMutableSet可以动态的添加集合元素,因此,创建NSMutableSet集合时可指定底层Hash表的 初始容量。
类似于NSMutableArray与NSArray的关系,NSMutableSet主要在NSSet基础上增加了添加元素、删除元素的方法,并增加了对集合计算交集、并集、差集的方法。

示例:

#import <Foundation/Foundation.h>

NSString* NSCollectionToString(id collection) {
    
    
    NSMutableString* result = [NSMutableString stringWithString:@"["];
    //使用快速枚举遍历NSSet集合
    for(id obj in collection) {
    
    
        [result appendString:[obj description]];
        [result appendString:@", "];
    }
    //获取字符串长度
    NSUInteger len = [result length];
    //去掉字符串最后的两个字符
    [result deleteCharactersInRange:NSMakeRange(len - 2 , 2)];
    [result appendString:@"]"];
    return result;
}


int main(int argc, const char * argv[]) {
    
    
    @autoreleasepool {
    
    
        NSMutableSet* set = [NSMutableSet setWithCapacity:10];
        [set addObject:@"疯狂iOS讲义"];
        NSLog(@"添加一个元素后,%@" , NSCollectionToString(set));
        [set addObjectsFromArray:[NSArray arrayWithObjects:@"疯狂Android讲义",
                                  @"疯狂Ajax讲义",
                                  @"疯狂XML讲义",
                                  nil]];
        NSLog(@"使用NSArray添加3个元素后:%@" , NSCollectionToString(set));
        [set removeObject:@"疯狂iOS讲义"];
        NSLog(@"删除一个元素后:%@" , NSCollectionToString(set));
        //再次创建一个NSSet集合
        NSSet* set2 = [NSSet setWithObjects:
                       @"孙悟空",
                       @"疯狂iOS讲义",nil];
        //计算两个集合的并集,直接改变set集合的元素
        [set unionSet:set2];
        //计算两个集合的差集,直接改变set集合的元素
        [set minusSet:set2];
        //计算两个集合的交集,直接改变set集合的元素
        [set intersectSet:set2];
        //用set2的集合元素替换set的集合元素,直接改变set集合的元素
        [set setSet:set2];
        NSLog(@"%@" , NSCollectionToString(set));
    }
    return 0;
}

效果:
在这里插入图片描述

NSCountedSet的功能与用法

NSCountedSet是NSMutableSet的子类,与普通NSMutableSet集合不同的是,NSCountedSet为每个元素额外维护一个添加次数的状态。当程序向NSCountedSet中添加一个元素时,如果NSCountedSet集合中不包含该元素,那么NSCountedSet真正接纳该元素,并将该元素的添加次数标注为1:当程序向NSCountedSet中添加一个元素时,如果NSCountedSet集合中已经包含该元素,那么NSCountedSet不会接纳该元素,但会将该元素的添加次数加一。 当程序从NSCountedSet集合中删除元素时,NSCountedSet只是将该元素的添加次数减一,只有当该元素的添加次数变为0时,该元素才会真正从NSCountedSet集合中删除。
NSCountedSet提供了如下方法来返回某个元素的添加次数:
countedForObject:获取指定元素的添加次数。

#import <Foundation/Foundation.h>
NSString* NSCollectionToString(id collection) {
    
    
    NSMutableString* result = [NSMutableString stringWithString:@"["];
    //使用快速枚举遍历NSSet集合
    for(id obj in collection) {
    
    
        [result appendString:[obj description]];
        [result appendString:@", "];
    }
    //获取字符串长度
    NSUInteger len = [result length];
    //去掉字符串最后的两个字符
    [result deleteCharactersInRange:NSMakeRange(len - 2 , 2)];
    [result appendString:@"]"];
    return result;
}


int main(int argc, const char * argv[]) {
    
    
    @autoreleasepool {
    
    
        NSCountedSet* set = [NSCountedSet setWithObjects:@"疯狂iOS讲义",
                             @"疯狂Android讲义",
                             @"疯狂Ajax讲义",nil];
        [set addObject:@"疯狂iOS讲义"];
        [set addObject:@"疯狂iOS讲义"];
        //输出集合元素
        NSLog(@"%@" , NSCollectionToString(set));
        //获取指定元素的添加次数
        NSLog(@"\"疯狂iOS讲义\"的添加次数为:%ld" , [set countForObject:@"疯狂iOS讲义"]);
        //删除元素
        [set removeObject:@"疯狂iOS讲义"];
        NSLog(@"删除\"疯狂iOS讲义\"1次后的结果:%@" , NSCollectionToString(set));
        NSLog(@"删除\"疯狂iOS讲义\"1次后的添加次数为:%ld" , [set countForObject:@"疯狂iOS讲义"]);
        
        //重复删除元素
        [set removeObject:@"疯狂iOS讲义"];
        [set removeObject:@"疯狂iOS讲义"];
        NSLog(@"删除\"疯狂iOS讲义\"3次后的结果:%@" , NSCollectionToString(set));
    }
    return 0;
}

效果:
在这里插入图片描述

Guess you like

Origin blog.csdn.net/weixin_50990189/article/details/117911002