NSArray简单细说(八)—— 数组的排序

版本记录

版本号 时间
V1.0 2017.08.25

前言

NSArray是集合类型中的一种,是OC中很重要的概念,这个是我们一定会用到的对象,下面我就继续由整体到细节,由简单到复杂的和大家说一下它的用法。感兴趣的可以看我写的上篇几篇。
1. NSArray简单细说(一)—— 整体了解
2. NSArray简单细说(二)—— 数组的创建
3. NSArray简单细说(三)—— 数组初始化
4. NSArray简单细说(四)—— 数组的查询与检索
5. NSArray简单细说(五)—— 数组中对象的查找
6. NSArray简单细说(六)—— 向数组中元素发送消息
7. NSArray简单细说(七)—— 数组的比较和获得新数组

一、@property(readonly, copy) NSData *sortedArrayHint;

该属性的作用就是:分析数组,并返回一个hint,当hint参数传递给sortedArrayUsingFunction: context:hint :时,可以加快数组的排序,上面调用的就是这个函数。

- (NSArray<ObjectType> *)sortedArrayUsingFunction:(NSInteger (*)(ObjectType, ObjectType, void *))comparator context:(void *)context hint:(NSData *)hint;

上面这个方法如何使用这里就不多说了,后面会和大家细说,下面我们看一下代码。

- (void)demoSortedArrayHint
{
    NSArray *arr = @[@1, @2, @3];
    NSData *data = [arr sortedArrayHint];
    NSLog(@"%@", data);
}

下面看输出结果

2017-08-25 21:13:01.514 JJOC[6905:176200] <b179379e 62f36e3c 136da6da>

这个大家是看不懂的,都是十六进制数据,后面会详细的和大家说的。

结论:不怎么用,但是还是要了解下。


二、- (NSArray<ObjectType> )sortedArrayUsingFunction:(NSInteger ()(ObjectType, ObjectType, void *))comparator context:(void *)context;

该方法的作用就是:返回一个新的数组,该数组是按照比较函数比较器定义的升序排列的。

还有一点需要注意:

  • 新数组包含对接收数组元素的引用,而不是它们的副本。比较函数用于一次比较两个元素,如果第一个元素小于第二个元素,则返回NSOrderedAscending,如果第一个元素大于第二个元素则返回NSOrderedDescending,如果元素相等则返回NSOrderedSame。 每次调用比较函数时,它将上下文作为第三个参数传递。 这允许比较基于一些外部参数,例如字符排序是区分大小写还是不区分大小写。

  • 给定一个Array(一个NSNumber对象的数组)和一个这种类型的比较函数,下面看代码

NSInteger intSort(id num1, id num2, void *context)
{
    int v1 = [num1 intValue];
    int v2 = [num2 intValue];
    if (v1 < v2)
        return NSOrderedAscending;
    else if (v1 > v2)
        return NSOrderedDescending;
    else
        return NSOrderedSame;
}

以这种方式创建Array的排序:

NSArray *sortedArray; 
sortedArray = [anArray sortedArrayUsingFunction:intSort context:NULL];

结论:还算好理解。


三、- (NSArray<ObjectType> )sortedArrayUsingFunction:(NSInteger ()(ObjectType, ObjectType, void *))comparator context:(void *)context hint:(NSData *)hint;

该方法的作用就是:返回一个新数组,按照比较函数比较器定义的升序列出接收数组的元素。

还有几点需要注意:

  • 新数组包含对接收数组元素的引用,而不是它们的副本。此方法类似于sortedArrayUsingFunction:context:,除了它使用提供的提示来加快排序过程。 当你知道数组几乎被排序时,这个方法比sortedArrayUsingFunction:context:更快。 如果您排序了一个大数组(N个条目)一次,并且不会更改它(P的添加和删除,P小于N),那么您可以通过概念上的方式重用您在原始排序中所做的工作 N个“旧”项目和P“新”项目之间的合并排序。
  • 要获得适当的提示,请使用sortedArrayHint。 当原始数组被排序后,您应该获取此提示,并在数组修改后保持该提示,直到需要它。 提示由O(N)中的sortedArrayHint计算(其中N是项目数)。 这假设数组中的项目实现了-hash方法。 给定一个合适的提示,并假设散列函数是一个“好”散列函数,-sortedArrayUsingFunction:context:hint:O(P * LOG(P)+ N)中对数组进行排序,其中P是添加或删除的数量。 当P较小时,这是一个非暗示类型O(N * LOG(N))的改进。
  • 提示只是一个包含N个哈希值的大小为N的数组。 要重新排序,您需要在内部创建映射表,将散列映射到索引。 在新数组中使用此映射表,您可以首先猜出索引,然后进行排序。 例如,具有相应散列值{25,96,78,32,17}的排序数组{A,B,D,E,F}可能经受小的变化,导致内容{E,A,C, B,F}。 映射表将散列{25,96,78,32,17}映射到索引{#0,#1,#2,#3,#4}。 如果{E,A,C,B,F}的散列是{32,25,99,96,17},那么通过使用映射表,您可以得到第一个排序{#3,#0,?, #1,#4},因此创建一个初始半排序数组{A,B,E,F},然后用{ C }执行便宜的合并排序,得到{A,B,C,E,F}

结论:这个确实需要好好的理解一下,有点设计算法的底层了。


四、- (NSArray<ObjectType> *)sortedArrayUsingDescriptors:(NSArray<NSSortDescriptor *> *)sortDescriptors;

该方法的作用就是:返回由给定的排序描述符数组指定的接收数组的副本。

下面我们就看一下参数和返回值:

  • sortDescriptorsNSSortDescriptor对象的数组。
  • return:按sortDescriptors指定排序的接收数组的副本。

还有几点需要注意:

  • 第一个描述符指定在对接收数组的内容进行排序时使用的主键路径。 任何后续描述符用于进一步改进具有重复值的对象的排序。 有关其他信息,请参阅NSSortDescriptor

下面我们看一下代码

- (void)demoSortedArrayUsingDescriptors
{
    NSDictionary *dic1 = [NSDictionary dictionaryWithObjectsAndKeys:@"2030",@"year", @"1",@"month",nil];
    NSDictionary *dic2 = [NSDictionary dictionaryWithObjectsAndKeys:@"2010",@"year", @"2",@"month", nil];
    NSDictionary *dic3 = [NSDictionary dictionaryWithObjectsAndKeys:@"2050",@"year", @"3",@"month" ,nil];
    NSDictionary *dic4 = [NSDictionary dictionaryWithObjectsAndKeys:@"2014",@"year",  @"4",@"month",nil];
    NSDictionary *dic5 = [NSDictionary dictionaryWithObjectsAndKeys:@"2050",@"year",  @"4",@"month",nil];
    
    NSArray *array = [NSArray arrayWithObjects:dic1, dic2, dic3, dic4, dic5, nil];
    
    NSSortDescriptor *descripor = [NSSortDescriptor sortDescriptorWithKey:@"year" ascending:NO];
    NSSortDescriptor *descripor2 = [NSSortDescriptor sortDescriptorWithKey:@"month" ascending:NO];
    NSArray *resultArr = [array sortedArrayUsingDescriptors:[NSArray arrayWithObjects:descripor, descripor2, nil]];
    
    NSLog(@"resultArr = %@", resultArr);
}

下面我们看一下输出结果

2017-08-25 22:35:36.342 JJOC[8148:226465] resultArr = (
        {
        month = 4;
        year = 2050;
    },
        {
        month = 3;
        year = 2050;
    },
        {
        month = 1;
        year = 2030;
    },
        {
        month = 4;
        year = 2014;
    },
        {
        month = 2;
        year = 2010;
    }
)

结论:这个还是经常会用到的,大家需要好好看看。


五、- (NSArray<ObjectType> *)sortedArrayUsingSelector:(SEL)comparator;

该方法的作用是:返回一个数组,按照由给定选择器指定的比较方法确定的升序列出接收数组的元素。

下面看一下参数和返回值:

  • comparator:标识用于一次比较两个元素的方法的选择器。 如果接收数组小于参数,则该方法应返回NSOrderedAscending,如果接收数组大于参数,NSOrderedDescending,如果相等则为NSOrderedSame
  • return:一个数组,由选择器比较器指定的比较方法确定,按照升序排列接收数组的元素。

还有几点需要注意:

  • 新数组包含对接收数组元素的引用,而不是它们的副本。
    比较器消息被发送到数组中的每个对象,并且在数组中具有另一个对象。例如,NSString对象的数组可以使用在NSString类中声明的caseInsensitiveCompare:方法进行排序。 假设存在anArray,则可以按以下方式创建数组的排序方式:
 NSArray *sortedArray = [anArray sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];

下面看完整代码

- (void)demoSortedArrayUsingSelector
{
    NSArray *arr = @[@"hello", @"how", @"are", @"you"];
    NSArray *resultArr = [arr sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
    NSLog(@"resultArr = %@", resultArr);
}

下面看输出结果

2017-08-25 22:59:07.430 JJOC[8986:249270] resultArr = (
    are,
    hello,
    how,
    you
)

结论:这个方法还是挺有意思的。


六、- (NSArray<ObjectType> *)sortedArrayUsingComparator:(NSComparator)cmptr;

该方法的作用就是:返回一个数组,按照由给定的NSComparator块指定的比较方法确定的升序列出接收数组的元素。

对于返回值,就是一个数组,按照指定的cmptr的比较方法,按升序列出接收数组的元素。

下面我们就看一下代码

- (void)demoSortedArrayUsingComparator
{
    NSArray *arr = @[@"hello", @"how", @"are", @"you"];
    NSArray *resultArr = [arr sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
         return [obj1 compare:obj2];
    }];
    NSLog(@"resultArr = %@", resultArr);
}

下面看输出结果

2017-08-25 23:10:48.071 JJOC[9363:257667] resultArr = (
    are,
    hello,
    how,
    you
)

上面这个就是按照升序进行排列的,那么按照降序呢,可以进行如下修改:

[obj2 compare:obj1];

下面看输出结果

2017-08-25 23:12:02.545 JJOC[9490:259440] resultArr = (
    you,
    how,
    hello,
    are
)

结论:这个总会用到,好好理解下就可以了,不难的。


七、- (NSArray<ObjectType> *)sortedArrayWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr;

该方法的作用就是:返回一个数组,按照由给定的NSComparator块指定的比较方法确定的升序列出接收数组的元素。

下面我们看一下参数和返回值:

  • opts:指定排序选项的位掩码(是否应同时执行以及是否应稳定执行)。这里是一个枚举,如下所示。
typedef NS_OPTIONS(NSUInteger, NSSortOptions) {
    NSSortConcurrent = (1UL << 0),
    NSSortStable = (1UL << 4),
};
  • cmptr:比较器的代码块。
  • return:一个数组,按照指定的cmptr的比较方法,按升序列出接收数组的元素。

下面我们看代码

- (void)demoSortedArrayWithOptions
{
    NSArray *arr = @[@"6", @"9", @"2", @"1"];
    NSArray *resultArr = [arr sortedArrayWithOptions:NSSortConcurrent usingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        return [obj1 compare:obj2];
    }];
    NSLog(@"resultArr = %@", resultArr);
}

下面看输出结果

2017-08-25 23:20:22.843 JJOC[9834:267493] resultArr = (
    1,
    2,
    6,
    9
)

结论:结合代码看,很好理解。

后记

未完,待续~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容