Fork me on GitHub

数字/字符排序及数据遍历快慢探究

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值.

posted @   极度恐慌_JG  阅读(393)  评论(0编辑  收藏  举报
编辑推荐:
· 从 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的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示