本文参阅 objc.io 文章 http://www.objc.io/issue-7/collections.html 而进行的总结。全文中文翻译:http://www.cocoachina.com/applenews/devnews/2014/0122/7735.html
测试环境设置: xcode5 ios7 64位 编译设置release为-Ofast;Vectorize loops and unroll loops 设置关闭
1、集合类一般都有两个版本:可变类型和不可变类型。其中不可变类型是完全线程安全的,而可变类型不能保证这一点。所以在API接口中,不应该返回可变类型的集合参数。有时候更有效的做法是:在程序内部保持一个可变类型的集合类对象,而返回一个复制的,不可变类型的集合类对象以供外部访问。
2、NSArray
①缩写的创建语法格式
//这两种创建 NSArray 的方式是相同的 NSArray *array_1 = @[@"hello",@"world"]; NSArray *array_2 = [NSArray arrayWithObjects:@"hello",@"world", nil];
②NSArray的对集合元素的下标操作
//这两种方式获取 NSArray 中元素是相同的 NSLog(@"print = %@",array_1[0]); NSLog(@"print = %@",[array_1 objectAtIndex:0]);
③在通过对一个array复制来创建一个可变数组的时候,由于源数组array可能为nil,所以创建的时候要考虑到nil的情况。
其正确的创建方式有:
NSArray *array = @[@"string1",@"string2"]; //方式1 NSMutableArray *mutableArray_1 = [array mutableCopy]; if (!mutableArray_1) { mutableArray_1 = [NSMutableArray array]; } //通过 三元运算符 ?: 简化方式1的写法 NSMutableArray *mutableArray_2 = [array mutableCopy]?:[NSMutableArray array]; //方式2 NSMutableArray *mutableArray_3 = [NSMutableArray arrayWithArray:array];
④对于创建NSMatableArray,介于代码的可读性,不要使用NSMutableArray *mutableArray = [@[]mutableCopy]; 这种方式创建;而要采用
NSArray *array = @[@"John Appleseed", @"Tim Cook", @"Hair Force One", @"Michael Jurewitz"]; NSArray *sortedArray = [array sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; [sortedArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"%zi --- %@",idx,obj); }]; NSArray *numbers = @[@9, @5, @11, @3, @1]; NSArray *sortedNumbers = [numbers sortedArrayUsingSelector:@selector(compare:)]; [sortedNumbers enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"%zi --- %@",idx,obj); }];输出结果:
2014-01-24 10:26:24.270 Foundation[871:303] 0 --- Hair Force One 2014-01-24 10:26:24.273 Foundation[871:303] 1 --- John Appleseed 2014-01-24 10:26:24.275 Foundation[871:303] 2 --- Michael Jurewitz 2014-01-24 10:26:24.276 Foundation[871:303] 3 --- Tim Cook 2014-01-24 10:26:24.277 Foundation[871:303] 0 --- 1 2014-01-24 10:26:24.277 Foundation[871:1003] 1 --- 3 2014-01-24 10:26:24.277 Foundation[871:1907] 2 --- 5 2014-01-24 10:26:24.280 Foundation[871:303] 3 --- 9 2014-01-24 10:26:24.280 Foundation[871:1003] 4 --- 11
#import <Foundation/Foundation.h> @interface Person : NSObject @property(nonatomic,strong)NSString* name; @property(nonatomic)int age; -(void)sortArray; @end
#import "Person.h" @implementation Person +(Person*)personWithAge:(int)age withName:(NSString*)name { Person* person = [[Person alloc]init]; person.age = age; person.name = name; return person; } //自定义排序方法 -(NSComparisonResult)comparePerson:(Person *)person{ //默认按年龄排序 NSComparisonResult result = [[NSNumber numberWithInt:person.age] compare:[NSNumber numberWithInt:self.age]]; //注意:基本数据类型要进行数据转换 //如果年龄一样,就按照名字排序 if (result == NSOrderedSame) { result = [self.name compare:person.name]; } return result; } -(void)sortArray { Person *p1 = [Person personWithAge:23 withName:@"zhangsan"]; Person *p2 = [Person personWithAge:21 withName:@"lisi"]; Person *p3 = [Person personWithAge:24 withName:@"wangwu"]; Person *p4 = [Person personWithAge:24 withName:@"liwu"]; Person *p5 = [Person personWithAge:20 withName:@"liwu"]; NSArray *array = [NSArray arrayWithObjects:p1,p2,p3,p4,p5, nil]; NSArray *sortedArray = [array sortedArrayUsingSelector:@selector(comparePerson:)]; [sortedArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"%zi --- %@ --- %d",idx,[obj name],[obj age]); }]; } @end调用执行 sortArray 方法。
2014-01-24 10:59:55.417 Foundation[1234:303] 0 --- liwu --- 24 2014-01-24 10:59:55.422 Foundation[1234:303] 1 --- wangwu --- 24 2014-01-24 10:59:55.424 Foundation[1234:303] 2 --- zhangsan --- 23 2014-01-24 10:59:55.425 Foundation[1234:303] 3 --- lisi --- 21 2014-01-24 10:59:55.425 Foundation[1234:303] 4 --- liwu --- 20注意到上面排序结果中是年龄是降序的,那么如果想要是升序结果的话,需要修改的地方是:
NSComparisonResult result = [[NSNumber numberWithInt:self.age] compare:[NSNumber numberWithInt:person.age]];
-(void)sortArray_1 { Person *p1 = [Person personWithAge:23 withName:@"zhangsan"]; Person *p2 = [Person personWithAge:21 withName:@"lisi"]; Person *p3 = [Person personWithAge:24 withName:@"wangwu"]; Person *p4 = [Person personWithAge:24 withName:@"liwu"]; Person *p5 = [Person personWithAge:20 withName:@"liwu"]; NSArray *array = [NSArray arrayWithObjects:p1,p2,p3,p4,p5, nil]; NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { NSComparisonResult result = [[NSNumber numberWithInt:[obj1 age]] compare:[NSNumber numberWithInt:[obj2 age]]]; if (result == NSOrderedSame) { result = [[obj1 name] compare:[obj2 name]]; } return result; }]; [sortedArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"%zi --- %@ --- %d",idx,[obj name],[obj age]); }]; }运行输出结果:
2014-01-24 13:09:24.963 Foundation[1581:303] 0 --- liwu --- 20 2014-01-24 13:09:24.968 Foundation[1581:303] 1 --- lisi --- 21 2014-01-24 13:09:24.968 Foundation[1581:303] 2 --- zhangsan --- 23 2014-01-24 13:09:24.969 Foundation[1581:303] 3 --- liwu --- 24 2014-01-24 13:09:24.970 Foundation[1581:303] 4 --- wangwu --- 24
#import "Car.h" @implementation Car +(Car *)initWithName:(NSString *)name{ Car *car = [Car alloc] init]; car.name = name; return car; } @end
在Person类中添加一个Car对象。
+(Person *)personWithAge:(int)age withName:(NSString *)name withCar:(Car *)car{ Person *person = [[Person alloc] init]; person.age = age; person.name = name; person.car = car; return person; }
-(void)sortArray_2 { //首先来3辆车,分别是奥迪、劳斯莱斯、宝马 Car *car1 = [Car initWithName:@"Audio"]; Car *car2 = [Car initWithName:@"Rolls-Royce"]; Car *car3 = [Car initWithName:@"BMW"]; //再来5个Person,每人送辆车,分别为car2、car1、car1、car3、car2 Person *p1 = [Person personWithAge:23 withName:@"zhangsan" withCar:car2]; Person *p2 = [Person personWithAge:21 withName:@"zhangsan" withCar:car1]; Person *p3 = [Person personWithAge:24 withName:@"lisi" withCar:car1]; Person *p4 = [Person personWithAge:23 withName:@"wangwu" withCar:car3]; Person *p5 = [Person personWithAge:23 withName:@"wangwu" withCar:car2]; //加入数组 NSArray *array = [NSArray arrayWithObjects:p1,p2,p3,p4,p5, nil]; //构建排序描述器 NSSortDescriptor *carNameDesc = [NSSortDescriptor sortDescriptorWithKey:@"car.name" ascending:YES]; NSSortDescriptor *personNameDesc = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]; NSSortDescriptor *personAgeDesc = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:YES]; //把排序描述器放进数组里,放入的顺序就是你想要排序的顺序 //我这里是:首先按照年龄排序,然后是车的名字,最后是按照人的名字 NSArray *descriptorArray = [NSArray arrayWithObjects:personAgeDesc,carNameDesc,personNameDesc, nil]; NSArray *sortedArray = [array sortedArrayUsingDescriptors: descriptorArray]; [sortedArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"%zi --- %@ --- %d --- %@",idx,[obj name],[obj age],[[obj car] name]); }]; }运行输出结果:
2014-01-24 13:04:06.008 Foundation[1552:303] 0 --- zhangsan --- 21 --- Audio 2014-01-24 13:04:06.012 Foundation[1552:303] 1 --- wangwu --- 23 --- BMW 2014-01-24 13:04:06.013 Foundation[1552:303] 2 --- wangwu --- 23 --- Rolls-Royce 2014-01-24 13:04:06.014 Foundation[1552:303] 3 --- zhangsan --- 23 --- Rolls-Royce 2014-01-24 13:04:06.016 Foundation[1552:303] 4 --- lisi --- 24 --- Audio
NSArray *array = @[@"string1",@"string2",@"string3"]; //方式一:普通的for循环 for (int i=0; i < [array count]; i++) { NSLog(@"%zi --- %@",i,[array objectAtIndex:i]); } //方式二:快输for循环 for (id obj in array) { NSLog(@"%zi --- %@",[array indexOfObject:obj],obj); } //方式三:使用block //1: enumerateObjectsUsingBlock 正序遍历 [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"%zi --- %@",idx,obj); }]; //2: enumerateObjectsUsingBlock 正序遍历:NSEnumerationConcurrent 反序遍历:NSEnumerationReverse [array enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"%zi --- %@",idx,obj); }]; [array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"%zi --- %@",idx,obj); }]; //方式四:利用枚举 NSEnumerator* en = [array objectEnumerator]; id obj = NULL; while (obj = [en nextObject]) { NSLog(@"%zi --- %@",[array indexOfObject:obj],obj); }
4、二分查找(要求数组已经排序)
typedef NS_OPTIONS(NSUInteger, NSBinarySearchingOptions) { NSBinarySearchingFirstEqual = (1UL << 8), NSBinarySearchingLastEqual = (1UL << 9), NSBinarySearchingInsertionIndex = (1UL << 10), }; - (NSUInteger)indexOfObject:(id)obj inSortedRange:(NSRange)r options:(NSBinarySearchingOptions)opts usingComparator:(NSComparator)cmp;
用法示例:
NSArray *sortedArray = ... // must be sorted id searchObject = ... NSRange searchRange = NSMakeRange(0, [sortedArray count]); NSUInteger findIndex = [sortedArray indexOfObject:searchObject inSortedRange:searchRange options:NSBinarySearchingFirstEqual usingComparator:^(id obj1, id obj2) { return [obj1 compare:obj2]; }];
5、枚举数组 Enumeration
// First variant, using `indexesOfObjectsWithOptions:passingTest:`. NSIndexSet *indexes = [randomArray indexesOfObjectsWithOptions:NSEnumerationConcurrent passingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { return testObj(obj); }]; NSArray *filteredArray = [randomArray objectsAtIndexes:indexes]; // Filtering using predicates (block-based or text) NSArray *filteredArray2 = [randomArray filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id obj, NSDictionary *bindings) { return testObj(obj); }]]; // Block-based enumeration NSMutableArray *mutableArray = [NSMutableArray array]; [randomArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { if (testObj(obj)) { [mutableArray addObject:obj]; } }]; // Classic enumeration NSMutableArray *mutableArray = [NSMutableArray array]; for (id obj in randomArray) { if (testObj(obj)) { [mutableArray addObject:obj]; } } // Using NSEnumerator, old school. NSMutableArray *mutableArray = [NSMutableArray array]; NSEnumerator *enumerator = [randomArray objectEnumerator]; id obj = nil; while ((obj = [enumerator nextObject]) != nil) { if (testObj(obj)) { [mutableArray addObject:obj]; } } // Using objectAtIndex: (via subscripting) NSMutableArray *mutableArray = [NSMutableArray array]; for (NSUInteger idx = 0; idx < randomArray.count; idx++) { id obj = randomArray[idx]; if (testObj(obj)) { [mutableArray addObject:obj]; } }
Enumeration Method / Time [ms] | 10.000.000 elements | 10.000 elements |
---|---|---|
indexesOfObjects: , concurrent |
1844.73 | 2.25 |
NSFastEnumeration (for in ) |
3223.45 | 3.21 |
indexesOfObjects: |
4221.23 | 3.36 |
enumerateObjectsUsingBlock: |
5459.43 | 5.43 |
objectAtIndex: |
5282.67 | 5.53 |
NSEnumerator |
5566.92 | 5.75 |
filteredArrayUsingPredicate: |
6466.95 | 6.31 |
//创建 字典 的两种方式 NSDictionary *dic_1 = [NSDictionary dictionaryWithObjectsAndKeys:@"value",@"key",@"value2",@"key2", nil]; NSDictionary *dic_2 = @{@"key": @"value",@"key2":@"value2"};
//根据key访问value的两种方式 NSLog(@"%@",[dic_1 objectForKey:@"key"]); NSLog(@"%@",dic_1[@"key"]);
7、枚举字典
// Using keysOfEntriesWithOptions:passingTest:,optionally concurrent NSSet *matchingKeys = [randomDict keysOfEntriesWithOptions:NSEnumerationConcurrent passingTest:^BOOL(id key, id obj, BOOL *stop) { return testObj(obj); }]; NSArray *keys = matchingKeys.allObjects; NSArray *values = [randomDict objectsForKeys:keys notFoundMarker:NSNull.null]; __unused NSDictionary *filteredDictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys]; // Block-based enumeration. NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary]; [randomDict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { if (testObj(obj)) { mutableDictionary[key] = obj; } }]; // NSFastEnumeration NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary]; for (id key in randomDict) { id obj = randomDict[key]; if (testObj(obj)) { mutableDictionary[key] = obj; } } // NSEnumeration NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary]; NSEnumerator *enumerator = [randomDict keyEnumerator]; id key = nil; while ((key = [enumerator nextObject]) != nil) { id obj = randomDict[key]; if (testObj(obj)) { mutableDictionary[key] = obj; } } // C-based array enumeration via getObjects:andKeys: NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary]; id __unsafe_unretained objects[numberOfEntries]; id __unsafe_unretained keys[numberOfEntries]; [randomDict getObjects:objects andKeys:keys]; for (int i = 0; i < numberOfEntries; i++) { id obj = objects[i]; id key = keys[i]; if (testObj(obj)) { mutableDictionary[key] = obj; } }
Filtering/Enumeration Method | Time [ms], 50.000 elements | 1.000.000 elements |
---|---|---|
keysOfEntriesWithOptions: , concurrent |
16.65 | 425.24 |
getObjects:andKeys: |
30.33 | 798.49* |
keysOfEntriesWithOptions: |
30.59 | 856.93 |
enumerateKeysAndObjectsUsingBlock: |
36.33 | 882.93 |
NSFastEnumeration |
41.20 | 1043.42 |
NSEnumeration |
42.21 | 1113.08 |
一.不可变集合NSSet
1.NSSet的初始化
创建一个集合
NSSet *set1 = [[NSSet alloc] initWithObjects:@"one", @"two", nil];
通过数组的构建集合
NSArray *array = [NSArrayWithObjects:@"1", @"2", @"3", nil];
NSSet *set2 = [[NSSet alloc] initWithArray:array];
通过已有集合构建集合
NSSet *set3 = [[NSSet alloc] initWithSet:set2];
2.NSSet常用方法
集合中对象的个数
int count = [set3 count];
以数组的形式返回集合中所有的对象
NSArray *allObjects = [set3 allObjects];
返回集合中的任意一个对象
id object = [set3 anyObject];
判断两个集合的元素中有包含的对象,包含返回YES,否则为NO
BOOL isContain = [set4 containsObject:@"2"];
判断两个集合的元素是否有相等的对象,存在返回YES,否则为NO
BOOL isIntersect = [set4 intersectsSet:set2];
判断两个集合的元素是否完全匹配,匹配返回YES,否则为NO
BOOL isEqual = [set4 isEqualToSet:set5];
集合4是否是集合5的子集合,如果是返回YES,否则为NO
BOOL isSubset = [set4 isSubsetOfSet:set5];
创建一个新的集合2,集合2有两个对象
NSSet *set1 = [NSSet setWithObjects:@"a",nil];
NSSet *set2 = [set1 setByAddingObject:@"b"];
通过已有的两个集合,创建新的一个集合
NSSet *set7 = [NSSet setWithObjects:@"a",nil];
NSSet *set8 = [NSSet setWithObjects:@"z",nil];
NSSet *set9 = [set7 setByAddingObjectsFromSet:set8];
通过已有的集合和数组对象,创建一个新的集合
NSArray *array = [NSArray arrayWithObjects:@"a",@"b",@"c",nil];
NSSet *set10 = [NSSet setWithObjects:@"z",nil];
NSSet *set11 = [set10 setByAddingObjectsFromArray:array];
二、可变集合NSMutableSet
常用方法
创建一个空的集合
NSMutableSet *set1 = [NSMutableSet set];
NSMutableSet *set2 = [NSMutableSet setWithObjects:@"1",@"2",nil];
NSMutableSet *set3 = [NSMutableSet setWithObjects:@"a",@"2",nil];
集合2减去集合3中的元素,集合2最后元素只有1个
[set2 minusSet:set3];
集合2与集合3中元素的交集,集合2最后元素只有1个
[set2 intersectSet:set3];
集合2与集合3中的元素的并集,集合2最后元素只有3个
[set2 unionSet:set3];
将空集合1设置为集合3中的内容
[set1 setSet:set3];
根据数组的内容删除集合中的对象
[set2 addObjectsFromArray:array];
[set2 removeObject:@"1"];
[set]2 removeAllObjects];
NSUInteger
is
either in the index set or isn’t. If you need to store an arbitrary number of integers that are not unique, better use an NSArray
.NSIndexSet *PSPDFIndexSetFromArray(NSArray *array) { NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet]; for (NSNumber *number in array) { [indexSet addIndex:[number unsignedIntegerValue]]; } return [indexSet copy]; }
使用block语法从NSIndexSet中获取索引:
NSArray *PSPDFArrayFromIndexSet(NSIndexSet *indexSet) { NSMutableArray *indexesArray = [NSMutableArray arrayWithCapacity:indexSet.count]; [indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { [indexesArray addObject:@(idx)]; }]; return [indexesArray copy]; }