enumerateObjectsUsingBlock、ForLoop、ForIn、EnumerateObjectsWithOptions PK
0. viewDidLoad中调用函数
- (void)viewDidLoad {
[super viewDidLoad];
//数字排序
[self numberSort];
//字符排序
[self charSort];
//遍历数组快慢 enumerateObjectsUsingBlock ForLoop ForIn
[self ForLoopAndForInAndEnumerateObjectsUsingBlock];
//通过Value查找Index快慢 ForIn EnumerateObjectsUsingBlock EnumerateObjectsWithOptions
[self ForInAndEnumerateObjectsUsingBlockAndEnumerateObjectsWithOptions];
//遍历字典快慢 ForIn enumerateKeysAndObjectsUsingBlock
[self ForInAndEnumerateKeysAndObjectsUsingBlock];
//数组的遍历 enumerateObjectsUsingBlock enumerateObjectsAtIndexes
[self enumArrayWithEnumBlockAndEnumIndexes];
}
1. 数字、字符比较排序
#pragma mark 比较/排序
#pragma mark - 字符排序 -
- (void)charSort {
UILabel *lable = [[UILabel alloc] initWithFrame:CGRectMake(10, 120, kDeviceWidth - 20, 50)];
lable.backgroundColor = [UIColor greenColor];
lable.numberOfLines = 0;
[self.view addSubview:lable];
NSArray *charArray = @[@"home",@"data",@"date",@"hello",@"key",@"jack"];
/*
对于NSStringCompareOptions,看看系统的说明:
enum{
NSCaseInsensitiveSearch = 1,//不区分大小写比较
NSLiteralSearch = 2,//区分大小写比较
NSBackwardsSearch = 4,//从字符串末尾开始搜索
NSAnchoredSearch = 8,//搜索限制范围的字符串
NSNumbericSearch = 64//按照字符串里的数字为依据,算出顺序。例如 Foo2.txt < Foo7.txt < Foo25.txt
//以下定义高于 mac os 10.5 或者高于 iphone 2.0 可用
,
NSDiacriticInsensitiveSearch = 128,//忽略 "-" 符号的比较
NSWidthInsensitiveSearch = 256,//忽略字符串的长度,比较出结果
NSForcedOrderingSearch = 512//忽略不区分大小写比较的选项,并强制返回 NSOrderedAscending 或者 NSOrderedDescending
//以下定义高于 iphone 3.2 可用
,
NSRegularExpressionSearch = 1024//只能应用于 rangeOfString:..., stringByReplacingOccurrencesOfString:...和 replaceOccurrencesOfString:... 方法。使用通用兼容的比较方法,如果设置此项,可以去掉 NSCaseInsensitiveSearch 和 NSAnchoredSearch
}
*/
NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch|NSNumericSearch|
NSWidthInsensitiveSearch|NSForcedOrderingSearch;
NSComparator sort = ^(NSString *obj1,NSString *obj2){
NSRange range = NSMakeRange(0,obj1.length);
return [obj1 compare:obj2 options:comparisonOptions range:range];
};
NSArray *resultArray2 = [charArray sortedArrayUsingComparator:sort];
// NSLog(@"字符串数组排序结果%@",resultArray2);
NSMutableString *muStr = [NSMutableString string];
[muStr appendString:@"(2) 字符串数组排序结果:\n"];
for (NSString *str in resultArray2) {
[muStr appendFormat:@"%@ -",str];
}
lable.text = muStr;
}
#pragma mark - 数字排序 -
- (void)numberSort {
UILabel *lable = [[UILabel alloc] initWithFrame:CGRectMake(10, 50, kDeviceWidth - 20, 50)];
lable.backgroundColor = [UIColor greenColor];
lable.numberOfLines = 0;
[self.view addSubview:lable];
NSArray *originalArray = @[@"1",@"21",@"12",@"11",@"0"];
//block比较方法,数组中可以是NSInteger,NSString(需要转换)
NSComparator finderSort = ^(id string1,id string2){
if ([string1 integerValue] > [string2 integerValue]) {
return (NSComparisonResult)NSOrderedDescending;
}else if ([string1 integerValue] < [string2 integerValue]){
return (NSComparisonResult)NSOrderedAscending;
}
else
return (NSComparisonResult)NSOrderedSame;
};
//数组排序:
NSArray *resultArray = [originalArray sortedArrayUsingComparator:finderSort];
// NSLog(@"第一种排序结果:%@",resultArray);
NSMutableString *muStr = [NSMutableString string];
[muStr appendString:@"(1) 数字排序结果:\n"];
for (NSString *str in resultArray) {
[muStr appendFormat:@"%@ -",str];
}
lable.text = muStr;
}
2. 遍历快慢
#pragma mark - 遍历字典快慢 -
- (void)ForInAndEnumerateKeysAndObjectsUsingBlock {
NSMutableDictionary *testDictionary = [NSMutableDictionary dictionary];
for (int i = 0; i < 1000; i++) {
NSString *valueStr = [NSString stringWithFormat:@"jack%04d",i];
NSString *keyStr = [NSString stringWithFormat:@"name%04d",i];
[testDictionary setValue:valueStr forKey:keyStr];
}
// NSLog(@"========== %@",testDictionary);
//For - in
NSMutableArray *forInArry = [NSMutableArray array];
double date_s = CFAbsoluteTimeGetCurrent();
NSArray *keys = [testDictionary allKeys];
for (NSString *key in keys) {
NSString *Value = testDictionary[key];
[forInArry addObject:Value];
}
double date_current = CFAbsoluteTimeGetCurrent() - date_s;
NSLog(@" For-in Time: %f ms",date_current * 1000);
//enumerateKeysAndObjectsUsingBlock
date_s = CFAbsoluteTimeGetCurrent();
NSMutableArray *enumArry = [NSMutableArray array];
[testDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
[enumArry addObject:obj];
}];
date_current = CFAbsoluteTimeGetCurrent() - date_s;
NSLog(@" enumerateBlock Time: %f ms",date_current * 1000);
//enumerateKeysAndObjectsWithOptions
date_s = CFAbsoluteTimeGetCurrent();
NSMutableArray * enumOptionArr = [NSMutableArray array];
[testDictionary enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id _Nonnull key, NSString *obj, BOOL * _Nonnull stop) {
[enumOptionArr addObject:obj];
}];
date_current = CFAbsoluteTimeGetCurrent() - date_s;
NSLog(@"enumerateOptions Time: %f ms",date_current * 1000);
// NSLog(@"ForInArr: %@",forInArry);
// NSLog(@"enumArry: %@",enumArry);
// NSLog(@"enumOptionArr: %@",enumOptionArr);
/*
输出结果:
For-in Time: 0.099003 ms
enumerateBlock Time: 0.070989 ms
enumerateOptions Time: 0.105023 ms
enumerateBlock更快
结论:
当我们想遍历字典类型的时候, 推荐使用enumerateBlock(经测试:大量数据enumerateBlock更快,若数据量较小For-in更快)
*/
}
#pragma mark - 通过Value查找Index快慢 -
- (void)ForInAndEnumerateObjectsUsingBlockAndEnumerateObjectsWithOptions {
NSMutableArray *test = [NSMutableArray array];
for (int i = 0; i < 10000000; i ++) {
[test addObject:@(i + 10)];
}
//For-in
__block NSInteger index = 0;
double date_s = CFAbsoluteTimeGetCurrent();
for (NSNumber *num in test) {
if ([num integerValue] == 9999999) {
index = [test indexOfObject:num];
break;
}
}
double date_current = CFAbsoluteTimeGetCurrent() - date_s;
NSLog(@"index : %ld For-in Time: %f ms",(long)index,date_current * 1000);
//enumerateObjectsUsingBlock
index = 0;
date_s = CFAbsoluteTimeGetCurrent();
[test enumerateObjectsUsingBlock:^(id num, NSUInteger idx, BOOL *stop) {
if ([num integerValue] == 9999999) {
index = idx;
*stop = YES;
}
}];
date_current = CFAbsoluteTimeGetCurrent() - date_s;
NSLog(@"index : %ld enumerateBlock Time: %f ms",(long)index,date_current * 1000);
//enumerateObjectsWithOptions
index = 0;
date_s = CFAbsoluteTimeGetCurrent();
[test enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id num, NSUInteger idx, BOOL *stop) {
if ([num integerValue] == 9999999) {
index = idx;
*stop = YES;
}
}];
date_current = CFAbsoluteTimeGetCurrent() - date_s;
NSLog(@"index : %ld enumerateObjectsWithOptions Time: %f ms",(long)index,date_current * 1000);
/*
输出结果:
index : 9999989 For-in Time: 572.869003 ms
index : 9999989 enumerateBlock Time: 439.854980 ms
index : 9999989 enumerateObjectsWithOptions Time: 279.659986 ms
enumerateObjectsWithOptions方法最快
结论:
通过Value查询index的时候, 面对大量的数组推荐使用 enumerateObjectsWithOptions的并行方法.
For-in和enumerateObjectsWithOptions方法这里我比较喜欢第二种写法简洁直观.
*/
}
#pragma mark - 遍历数组快慢 -
- (void)ForLoopAndForInAndEnumerateObjectsUsingBlock {
NSMutableArray *muArrM = [NSMutableArray array];
for (int i = 0; i < 1000000; i++) {
[muArrM addObject:@(i)];
}
__block int sum = 0;
double date_s = CFAbsoluteTimeGetCurrent();
for (int i = 0; i < muArrM.count; i++) {
sum += [muArrM[i] integerValue];
}
double date_current = CFAbsoluteTimeGetCurrent() - date_s;
NSLog(@"Sum : %d forLoop Time : %f ms",sum, date_current * 1000);
sum = 0;
date_s = CFAbsoluteTimeGetCurrent();
for (NSNumber *num in muArrM) {
sum += [num integerValue];
}
date_current = CFAbsoluteTimeGetCurrent() - date_s;
NSLog(@"Sum : %d ForIn Time: %f ms",sum, date_current * 1000);
sum = 0;
date_s = CFAbsoluteTimeGetCurrent();
[muArrM enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
sum += [obj integerValue];
}];
date_current = CFAbsoluteTimeGetCurrent() - date_s;
NSLog(@"Sum: %d enumrateBlock Time:%f ms", sum, date_current * 1000);
/*
输出结果:
Sum : 1783293664 forLoop Time : 30.366004 ms
Sum : 1783293664 ForIn Time: 13.710976 ms
Sum: 1783293664 enumrateBlock Time:44.068038 ms
For-in方法最快速
结论:
当只是遍历一个数组的时候使用ForIn会比较快速, 推荐使用For-in遍历数组.
*/
}
3. 数组的遍历
#pragma mark - enumArrayWithEnumBlockAndEnumIndexes -
- (void)enumArrayWithEnumBlockAndEnumIndexes {
//对数组中元素块操作
NSArray* array = @[@"aa",@"bb",@"cc",@"dd",@"ee",@"ff",@"gg"];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"%@ - %lu",obj,idx);
}];
NSLog(@"-----enumerateObjectsUsingBlock--------- ");
//NSIndexSex 是取值范围 (NSMakeRange(1, 4)前面数字代表从哪个位置开始取,后面数字代表取的长度)
//options为NSEnumerationReverse倒序,NSEnumerationConcurrent正序
[array enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 4)] options:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"%@ - %lu",obj, idx);
}];
NSLog(@"-----enumerateObjectsAtIndexes--------- ");
}
enumerateObjectsUsingBlock VS for(... in ...)
for(... in ...)用起来非常方便、简洁,同时
enumerateObjectsUsingBlock:
也有很多新特性:
-
通常enumerateObjectsUsingBlock:
和 (for(... in ...)在效率上基本一致,有时会快些。主要是因为它们都是基于
NSFastEnumeration
实现的. 快速迭代在处理的过程中需要多一次转换,当然也会消耗掉一些时间. 基于Block的迭代可以达到本机存储一样快的遍历集合. 对于字典同样适用,而数组的迭代却不行。 -
注意"enumerateObjectsUsingBlock" 修改局部变量时, 你需要声明局部变量为
__block 类型
. -
enumerateObjectsWithOptions:usingBlock:
支持并发迭代或反向迭代,并发迭代时效率也非常高. -
对于字典而言,
enumerateObjectsWithOptions:usingBlock
也是唯一的方式可以并发实现恢复Key-Value值.