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

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) 字符串数组排序结果:
"];
    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) 数字排序结果:
"];
    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值.

原文地址:https://www.cnblogs.com/GJ-ios/p/5852140.html