SkillAgentSearch skills...

SortingForArray

Demo·必会的算法操作:字符串数组排序+模型对象数组排序

Install / Use

/learn @cimain/SortingForArray
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

iOS开发·必会的算法操作:字符串数组排序+模型对象数组排序

前面的话

为了给字符串数组排序,除了用C/C++的基本办法,iOS开发者更应该学会利用苹果专门为NSArray 排序提供的sortedArrayUsingComparator 方法:

- (NSArray<ObjectType> *)sortedArrayUsingComparator:(NSComparator NS_NOESCAPE)cmptr NS_AVAILABLE(10_6, 4_0);

其中,需要设置一个NSComparator 参数,它是一个block,查看定义如下:

typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);

这个block体返回的NSComparisonResult 是一个枚举类型,它的定义是:

typedef NS_ENUM(NSInteger, NSComparisonResult) {NSOrderedAscending = -1L, NSOrderedSame, NSOrderedDescending};

问题来了,怎么设置?

  • 为了设置这个NSComparator 参数的block体,你可以在设置其block体的时候,手动返回一个NSComparisonResult 枚举类型的某个具体值(NSOrderedAscending, NSOrderedSame, NSOrderedDescending 三选一):

image.png

  • 如果数组里面是字符串,在设置其block体的时候,你也可以利用苹果专门为NSString 提供的字符串比较方法,获得一个NSComparisonResult 类型,将其自动返回。
- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)rangeOfReceiverToCompare locale:(nullable id)locale; // locale arg used to be a dictionary pre-Leopard. We now accept NSLocale. Assumes the current locale if non-nil and non-NSLocale. nil continues to mean canonical compare, which doesn't depend on user's locale choice.

image.png

这时候,就需要了解NSStringCompareOptions 的意思。但如果你搜索一下NSStringCompareOptions ,会发现很多文章中的翻译或者中文解释在误导,或者很难看清什么意思?例如下面这篇博客:

image.png

然后,相同的解释文案还以讹传讹的传开来了,例如你看下面这个博客:

image.png

于是,笔者决定写此本文,好好展示他们的用途。

1. 第一种:数组的字符串元素里面是基本数据类型


1.1 字符串数组排序示例

1.1.1 实验代码
  • main.m
void handleSortingForIntStrArray(void){
    NSArray *originalArray = @[@"00",@"0",@"00",@"01",@"10",@"21",@"12",@"11",@"22"];
    //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);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Results of handleSortingForIntArray()**********************");
        handleSortingForIntStrArray();
    }
    return 0;
}
1.1.2 运行结果

image.png

1.1.3 实验结论
  • 依据数组元素的数值大小返回升序数组

1.2 NSComparator与NSComparisonResult

上面的代码中用到了NSComparator与NSComparisonResult,在本文的“前面的话”中已经介绍过,这里重新列一下定义。

1.2.1 NSComparator
typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);
1.2.2 NSComparisonResult
typedef NS_ENUM(NSInteger, NSComparisonResult) {NSOrderedAscending = -1L, NSOrderedSame, NSOrderedDescending};

2. 第二种:数组的字符串元素里面不是基本数据类型


2.1 示例:字符串数组排序

2.1.1 实验代码
  • main.m
//
//  main.m
//  SortingForArray
//
//  Created by ChenMan on 2017/12/20.
//  Copyright © 2017年 ChenMan. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <stdio.h>

void handleSortingForStrArray(void){
       NSArray *stringsArray = [NSArray arrayWithObjects:
                             @"string b",
                             @"string A",
                             @"string a",
                             @"string \uFF41",
                             @"string a",
                             @"string A",
                             @"string c",
                             @"string d0030",
                             @"string d2",
                             @"アいろはアイウエイウエ",
                             @"アいろはアイウエイウエ",
                             @"アいろはアイウエイウエ",nil];
    
    NSLocale *currentLocale = [NSLocale currentLocale];
    NSComparator finderSortBlock = ^(id string1,id string2) {
        
        NSRange string1Range =NSMakeRange(0, [string1 length]);
        return [string1 compare:string2 options:nil range:string1Range locale:currentLocale];
    };
    
    NSArray *finderSortArray = [stringsArray sortedArrayUsingComparator:finderSortBlock];
    NSLog(@"finderSortArray: %@", finderSortArray);
    
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Results of handleSortingForStrArray()**********************");
        handleSortingForStrArray();
    }
    return 0;
}
2.1.2 运行结果:

image.png

2.1.3 实验结论:

如上实验代码中,有这样一行代码:

return [string1 compare:string2 options:nil range:string1Range locale:currentLocale];

根据运行结果,可知如下结论:

  • 即使在- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask range:(NSRange)rangeOfReceiverToCompare locale:(nullable id)locale; 中将(NSStringCompareOptions)枚举类型的参数设置为nil,也可以运行。但一般不这么做,这里只是为了观察不指定该枚举参数时候系统的默认设置,并与本文接下来指定该枚举参数的排序结果对比。
  • 可以发现:
    • 默认同一字符的全角字符看做半角字符。不区分同一个字符(如日文的片假字)的半角与全角状态。相同元素,维持原序。
    • 默认区分字母大小写,同一个字符小写在前,大写在后。
    • 字母并非按unicode码的大小升序排列。例如,全角a的unicode为FF41,半角a的unicode为0061,半角A的unicode为0041,半角b的unicode为0062,但排序结果是 全角a = 半角a < 半角A < 半角b
    • 默认不识别含有数字字符的数值大小,0030虽然数学意义比2大,但是,仅从字符串的角度看,第一个字符0比2小,所以d0030排在d2前面。
2.1.4 知识拓展:

半角与全角字符

  • 全角占两个字节,半角占一个字节。通常我们碰到的英文字母、数字键、符号键这种ASCII码系统里面的字符大多数情况下是半角的。

  • 国内汉字输入法输入的汉字为全角,字母数字为半角,但是标点则默认为全角,可切换为半角(可以通过输入法工具条上的相应按钮来切换标点符号的全角半角状态)。

  • 日文里面的有汉字,也有片假字。这个片假字有两套编码,同一个片假字分别有半角和全角两种编码。例如:看起来像一样的片假字组成的句子,全角状态字符开头的为アいろはアイウエイウエ,半角状态字符开头的为アいろはアイウエイウエ。可以看到,明显同一个片假字的全角状态半角状态 “胖”一圈。

  • 英文字母其实也有全角字母,例如小写的a,其半角形式的unicode码为0061,其全角形式的unicode码为FF41。可查阅Unicode®字符百科官网。

2.2 NSStringCompareOptions

NSStringCompareOptions是一个枚举类型,并非一个类。打开NSStringCompareOptions的定义,可查看如下

typedef NS_OPTIONS(NSUInteger, NSStringCompareOptions) {
    NSCaseInsensitiveSearch = 1,
    NSLiteralSearch = 2,		/* Exact character-by-character equivalence */
    NSBackwardsSearch = 4,		/* Search from end of source string */
    NSAnchoredSearch = 8,		/* Search is limited to start (or end, if NSBackwardsSearch) of source string */
    NSNumericSearch = 64,		/* Added in 10.2; Numbers within strings are compared using numeric value, that is, Foo2.txt < Foo7.txt < Foo25.txt; only applies to compare methods, not find */
    NSDiacriticInsensitiveSearch API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)) = 128, /* If specified, ignores diacritics (o-umlaut == o) */
    NSWidthInsensitiveSearch API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)) = 256, /* If specified, ignores width differences ('a' == UFF41) */
    NSForcedOrderingSearch API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)) = 512, /* If specified, comparisons are forced to return either NSOrderedAscending or NSOrderedDescending if the strings are equivalent but not strictly equal, for stability when sorting (e.g. "aaa" > "AAA" with NSCaseInsensitiveSearch specified) */
    NSRegularExpressionSearch API_AVAILABLE(macos(10.7), ios(3.2), watchos(2.0), tvos(9.0)) = 1024    /* Applies to rangeOfString:..., stringByReplacingOccurrencesOfString:..., and replaceOccurrencesOfString:... methods only; the search string is treated as an ICU-compatible regular expression; if set, no other options can apply except NSCaseInsensitiveSearch and NSAnchoredSearch */
};
2.2.1 NSNumericSearch

官方解释:Added in 10.2; Numbers within strings are compared using numeric value, that is, Foo2.txt < Foo7.txt < Foo25.txt; only applies to compare methods, not find

  • 假设,将上例中的部分代码修改为
void handleSortingForStrArray(void){
    NSArray *stringsArray = [NSArray arrayWithObjects:
                             @"string b",
                             @"string A",
                             @"string a",
                             @"string \uFF41",
                             @"string a",
                             @"string A",
                             @"string c",
                             @"string d0030",
                             @"string d2",
                             @"アいろはアイウエイウエ",
                             @"アいろはアイウエイウエ",
                             @"アいろはアイウエイウエ",nil];
    NSStringCompareOptions comparisonOptions = NSNumericSearch;
    NSLocale *currentLocale = [NSLocale currentLocale];
    NSComparator finderSortBlock = ^(id string1,id string2) {
        
        NSRange string1Range =NSMakeRange(0, [string1 length]);
        return [string1 compare:string2 options:comparisonOptions range:string1Range locale:currentLocale];
    };
    
    NSArray *finderSortArray = [stringsArray sortedArrayUsingComparator:finderSortBlock];
    NSLog(@"finderSortArray: %@", finderSortArray);
}
  • 运行结果

image.png

  • 结论 NSStringCompareOptions指定为NSNumericSearch,当字符串中含有数字时,从数值大小的角度按升序排序。
2.2.2 NSCaseInsensitiveSearch

官方解释:无。英文字面解释:不区分字母大小写。

  • 假设,将上例中的部分代码修改为
NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch; 
  • 运行结果

image.png

  • 结论 NSStringCompareOptions指定为NSCaseInsensitiveSearch,不区分同一个字母的大小写状态,如aA看做相同元素,若其它条件也一致则保持原序。
2.2.3 NSLiteralSearch

官方解释:Exact character-by-character equivalence

  • 假设,将上例中的部分代码修改为
NSStringCompareOptions comparisonOptions = NSLiteralSearch;
  • 运行结果

![image.png](https://user-gold-cd

Related Skills

View on GitHub
GitHub Stars38
CategoryDevelopment
Updated1mo ago
Forks11

Languages

Objective-C

Security Score

80/100

Audited on Feb 23, 2026

No findings