您的位置:首页 > 移动开发 > IOS开发

【iOS开发系列】NSSet & NSIndexSet

2015-07-14 20:24 645 查看
NSSet

NSSet和NSMutableSet是无序的, 但是它保证数据的唯一性。当插入相同的数据时,不会有任何效果。从内部实现来说是hash表,所以可以常数时间内查找一个数据。



1、NSSet的使用

[NSSet setWithSet:(NSSet *)set]; 用另外一个set对象构造

[NSSet setWithArray:(NSArray *)array];用数组构造

[NSSet setWithObjects:...]:创建集合对象,并且初始化集合中的数值,结尾必需使用nil标志。

[set count] ; 得到这个结合对象的长度。

[set containsObject:...]: 判断这个集合中是否存在传入的对象,返回Bool值。

[set objectEnumerator]: 将集合放入迭代器。

[enumerator nextObject]:得到迭代器中的下一个节点数据,使用while遍历这个迭代器,方可遍历集合对象中的对象。

[set isEqualToSet:objset]:判断两个集合是否完全相等,返回Bool值。

[set isSubsetOfSet:objset]:判断集合中的所有数据是否都相等与objeset集合中,返回Bool值。

[set allObjects];

示例代码:

1.1 以NSArray构造set

NSArray *array = [[NSArray alloc] initWithObjects:@"对象abc",@"rongfzh", @"totogo2010",nil];
NSSet *set3 = [NSSet setWithArray:array];
NSLog(@"%@", set3);


打印:

1.2 set的一些比较方法的使用。

int main(int argc, const char * argv[])
{
@autoreleasepool {
NSSet *set = [NSSet setWithObjects:@"25",@"age",@"张三",@"name",@"男",nil];
NSSet *set1 = [NSSet setWithObjects:@"25",@"age",@"张三",@"name",@"男",@"性别",nil];

NSLog(@"set count:%lu", [set count]);
//判断是否含有age字符串
if([set containsObject:@"age"]) {
NSLog(@"set包含age");
}
//判断set 是否等于set1
if ([set isEqualToSet:set1]) {
NSLog(@"set 等于 set1");
}
//判断set是否是否是set1的子集合
if ([set isSubsetOfSet:set1]) {
NSLog(@"set isSubsetOfSet set1");
}
//获取所有set对象
NSArray *array = [set allObjects];
NSLog(@"array:%@", array);

//迭代遍历
NSEnumerator *enumerator = [set objectEnumerator];
for (NSObject *object in enumerator) {
NSLog(@"set1里的对象:%@", object);
}
}
return 0;
}


打印结果:

2、NSMutableSet的使用

NSMutableSet继承NSSet,它可以使用NSSet的方法。

[NSMutableSet setWithCapacity:6]:创建可变集合对象,并且初始化长度为6。

[set addObject: obj] : 向集合中动态的添加对象。

[set removeObject:obj]:删除集合中的一个对象。

[set removeAllObjects]:删除集合中的所有对象。

[set unionSet:obj]:向集合中添加一个obj集合的所有数据。

[set minusSet:obj]:向集合中删除一个obj集合的所有数据。

[set intersectSet]:向集合中删除一个不包含obj集合的所有数据。

int main(int argc, const char * argv[])
{
@autoreleasepool {
NSMutableSet *muSet = [NSMutableSet setWithCapacity:6];
[muSet addObject:@"对象1"];
NSSet *set = [NSSet setWithObjects:@"对象2",@"对象3", @"被企鹅咬了一口", nil];
//添加set数据
[muSet unionSet:set];
for (NSObject *object in muSet) {
NSLog(@"all nuSet:%@",object);
}
NSSet *set1 = [NSSet setWithObjects:@"对象2",@"对象3", nil];

//在muSet中删除包含set1总数据
[muSet minusSet:set1];
for (NSObject *object in muSet) {
NSLog(@"after minusSet:%@",object);
}

}
return 0;
}


打印结果:

NSSet和NSArray的区别

NSSet到底什么类型,其实它和NSArray功能性质一样,用于存储对象,属于集合; NSSet , NSMutableSet类声明编程接口对象,无序的集合,在内存中存储方式是不连续的,不像NSArray,NSDictionary(都是有序的集合)类声明编程接口对象是有序集合,在内存中存储位置是连续的;

NSSet和我们常用NSArry区别是:在搜索一个一个元素时NSSet比NSArray效率高,主要是它用到了一个算法hash(散列,也可直译为哈希);开发文档中这样解释:You can use sets as an alternative to
arrays when the order of elements isn’t important and performance in testing whether an object is contained in the set is a consideration—while arrays are ordered, testing for membership is slower than with sets.

比如你要存储元素A,一个hash算法直接就能直接找到A应该存储的位置;同样,当你要访问A时,一个hash过程就能找到A存储的位置。而对于NSArray,若想知道A到底在不在数组中,则需要便利整个数组,显然效率较低了;

NSSet,NSArray都是类,只能添加cocoa对象,如果需要加入基本数据类型(int,float,BOOL,double等),需要将数据封装成NSNumber类型。

NSIndexSet使用解析

NSIndexSet可以用来存储一系列的索引值区间,索引值可以使用单个的NSUInteger或者NSRange来表示。而且和许多其他集合类型一样,它有不可变和可变的执行,分别对应NSIndexSet类型和NSMutableIndexSet类型。NSIndexSet可以通过一个NSUinteger,NSRange或者另一个NSIndexSet来创建。也可以使用NSMutableIndexSet来多次添加NSUinteger或者NSRange对象。
比如创建一个NSMutableIndexSet对象,加入数据,然后枚举所有的索引值:

NSMutableIndexSet *idxSet = [[NSMutableIndexSet alloc] init];

//添加5和2

[idxSet addIndex:5];

[idxSet addIndex:2];

//添加7-10

[idxSet addIndexesInRange:NSMakeRange(7, 4)];

[idxSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop)

{

NSLog(@"%lu", (unsigned long)idx);

}];


输出:

2
5
7
8
9
10

NSIndexSet还支持其他方式的枚举方法,比如可以取一个NSRange范围中的交集,然后还可以以相反的顺序进行枚举。

这个需求需要使用NSIndexSet的enumerateIndexesInRange:options:usingBlock:方法,如下代码:

NSMutableIndexSet *idxSet = [[NSMutableIndexSet alloc] init];

//添加5和2

[idxSet addIndex:5];

[idxSet addIndex:2];

//添加7-10

[idxSet addIndexesInRange:NSMakeRange(7, 4)];

//idxSet包含的区间:2, 5, 7 - 10

//取交集:3 – 8

[idxSet enumerateIndexesInRange:NSMakeRange(3, 6) options:NSEnumerationReverseusingBlock:^(NSUInteger idx, BOOL *stop)

{

NSLog(@"%lu", (unsigned long)idx);

}];

输出:

8
7
5

由于NSIndexSet本身的区间是:2,5,7 – 10。然后取交集的区间是3 – 8。最后倒序枚举,所以会输出8,7,5。

NSIndexSet同时还包含许多方法判断是否包含某区间或者从一个索引值内获取临近的区间内的索引。如下代码:

NSMutableIndexSet *idxSet = [[NSMutableIndexSet alloc] init];

//添加5和2

[idxSet addIndex:5];

[idxSet addIndex:2];

//判断是否包含3 - 5

NSLog(@"%d", [idxSet containsIndexesInRange:NSMakeRange(3, 2)]);

//从4起找到最近的等于或者大于的索引值

NSLog(@"%lu", (unsigned long)[idxSet indexGreaterThanOrEqualToIndex:4]);
输出:

0
5

还可以使用NSIndexSet的indexesInRange:options:passingTest:方法来根据要求返回另一个NSIndexSet。操作过程和上面讲的enumerateIndexesInRange:options:usingBlock:方法类似,只不过Block参数需要返回一个BOOL,通过这个BOOL来决定元素是否被加入到返回的NSIndexSet对象中。

代码:

NSMutableIndexSet *idxSet = [[NSMutableIndexSet alloc] init];

//添加5和2

[idxSet addIndex:5];

[idxSet addIndex:2];

//添加7-10

[idxSet addIndexesInRange:NSMakeRange(7, 4)];

//从NSRange的交集中倒着枚举

NSIndexSet *subSet = [idxSet indexesInRange:NSMakeRange(3, 6) options:NSEnumerationReverse passingTest

^BOOL(NSUInteger idx, BOOL *stop)

{

NSLog(@"> %lu", (unsigned long)idx);

return idx % 2;

}];

//枚举subSet

[subSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop)

{

NSLog(@"%lu", (unsigned long)idx);

}];
输出:

> 8
> 7
> 5
5
7

最后的方法就是NSArray的objectsAtIndexes,该方法可以根据一个NSIndexSet所在的区间返回数组相应的成员。

代码:

NSMutableIndexSet *idxSet = [[NSMutableIndexSet alloc] init];

[idxSet addIndex:2];

[idxSet addIndexesInRange:NSMakeRange(5, 3)];

NSArray *arr = @[@0, @1, @2, @3, @4, @5, @6, @7, @8, @9];

NSArray *res = [arr objectsAtIndexes:idxSet];

for(id item in res) {

NSLog(@"%@", item);

}
输出:

2
5
6
7
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: