数字/字符排序及数据遍历快慢探究
enumerateObjectsUsingBlock、ForLoop、ForIn、EnumerateObjectsWithOptions PK
0. viewDidLoad中调用函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | - ( 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. 数字、字符比较排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | #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. 遍历快慢
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | #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. 数组的遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #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值.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~