iOS NSArray的排序

5,613 阅读4分钟

OC中常用的数组排序有三种:

sortedArrayUsingSelector(简单排序)
sortedArrayUsingComparator(利用block语法)
sortedArrayUsingDescriptors(高级排序)

一: 简单排序(sortedArrayUsingSelector)

如果只是对字符串进行简单的排序, 可以利用sortedArrayUsingSelector:方法就可以了,代码如下:

NSArray *array = @[@"d",@"e",@"a",@"c",@"m",@"h"];
NSLog(@"array = %@",[array sortedArrayUsingSelector:@selector(compare:)]);
//输出:(a,c,d,e,h,m)

当然, 除了利用字符串自带的compare:方法, 也可以自己写compare:方法, 进行对象的比较; 如下:

首先是新建Person类, .h文件如下:

@interface Person : NSObject
//年龄
@property (nonatomic, assign) int age;
//名字
@property (nonatomic, strong) NSString *name;

//直接实现静态方法, 获取带有name和age的Person对象
+ (Person *)personWithAge:(int)age withName:(NSString *)name;

//自定义排序方法
- (NSComparisonResult)comparePerson:(Person *)person;
@end

.m文件如下:

#import "Person.h"

@implementation Person

//直接实现静态方法, 获取带有name和age的Person对象
+ (Person *)personWithAge:(int)age withName:(NSString *)name {
    Person *person = [[Person alloc] init];
    person.age = age;
    person.name = name;
    return person;
}

//自定义排序方法
- (NSComparisonResult)comparePerson:(Person *)person {    
    //默认按年龄排序
    //注意: 基本数据类型要进行数据转换
    NSComparisonResult result = [[NSNumber numberWithInt:self.age] compare:[NSNumber numberWithInt:person.age]];
    //如果年龄一样, 就按照名字排序
    if (result == NSOrderedSame) {
        result = [self.name compare:person.name];
    }
    return  result;
}

@end

主函数代码:

Person *p1 = [Person personWithAge:23 withName:@"zhaoyi"];
Person *p2 = [Person personWithAge:21 withName:@"qianer"];
Person *p3 = [Person personWithAge:24 withName:@"zhangsan"];
Person *p4 = [Person personWithAge:24 withName:@"lisi"];
Person *p5 = [Person personWithAge:20 withName:@"wangwu"];
    
NSArray *array = [NSArray arrayWithObjects:p1, p2, p3, p4, p5, nil];
NSArray<Person *> *sortedArray = [array sortedArrayUsingSelector: @selector(comparePerson:)];
[sortedArray enumerateObjectsUsingBlock:^(Person *  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    NSLog(@"排序后的年龄: %d, 名字: %@",obj.age, obj.name);
}];

输出:
排序后的年龄: 20, 名字: wangwu
排序后的年龄: 21, 名字: qianer
排序后的年龄: 23, 名字: zhaoyi
排序后的年龄: 24, 名字: lisi
排序后的年龄: 24, 名字: zhangsan

二: 利用block语法(sortedArrayUsingComparator)

苹果官方提供了block语法, 比较方便. 其中数组排序可以用sortedArrayUsingComparator:方法, 代码如下:

NSArray *array = @[@"cda", @"efj", @"iqw", @"adb", @"lcd", @"hil"];
NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
    //这里的代码可以参照上面compare: 默认的排序方法, 也可以把自定义的方法写在这里, 给对象排序
    NSComparisonResult result = [obj1 compare:obj2];
    return result;
}];
NSLog(@"排序后数组: %@",sortedArray);
    
输出:(adb, cda, efj, hil, iqw, lcd)

三:高级排序:

如果是这样一种情况呢? Person类里有另外一个类的变量, 比如说Person类除了name, age变量, 还有一辆车Car类型, Car类里有个name属性. 对Person对象进行排序, 有这样的要求:按照Car的name排序, 如果是同一辆车, 也就是Car的name相同, 那么再按照年龄进行排序, 如果年龄也相同, 最后按照Person的name进行排序.

上面这种情况, 就要使用第三种方法, 利用排序描述器了.代码如下: 首先写个Car类, .h文件如下:

@interface Car : NSObject
/** 汽车名字 */
@property (nonatomic, strong) NSString *name;

+ (Car *)initWithName:(NSString *)name;
@end

.m文件如下:

#import "Car.h"

@implementation Car

+ (Car *)initWithName:(NSString *)name {
    Car *car = [[Car alloc] init];
    car.name = name;
    return car;
}

@end

Person类的.h文件, 代码如下:

@interface Person : NSObject
//年龄
@property (nonatomic, assign) int age;
//名字
@property (nonatomic, strong) NSString *name;
//汽车
@property (nonatomic, strong) Car *car;


+ (Person *)personWithAge:(int)age withName:(NSString *)name withCar:(Car *)car;
@end

Person类的.m文件, 代码如下:

#import "Person.h"

@implementation Person

//直接实现静态方法, 获取带有name和age的Person对象
+ (Person *)personWithAge:(int)age withName:(NSString *)name {
    Person *person = [[Person alloc] init];
    person.age = age;
    person.name = name;
    return person;
}

+ (Person *)personWithAge:(int)age withName:(NSString *)name withCar:(Car *)car {
    Person *person = [[Person alloc] init];
    person.age = age;
    person.name = name;
    person.car = car;
    return person;
}

//这里重写description方法, 用于最后测试排序结果显示
- (NSString *)description {
    return [NSString stringWithFormat:@"age is %d, name is %@, car.name is %@",_age, _name, _car.name];
}

@end

主函数代码如下:

Car *car1 = [Car initWithName:@"Audio"];
Car *car2 = [Car initWithName:@"Rolls-Royce"];
Car *car3 = [Car initWithName:@"BMW"];
    
Person *p1 = [Person personWithAge:23 withName:@"zhaoyi" withCar:car2];
Person *p2 = [Person personWithAge:21 withName:@"qianer" withCar:car1];
Person *p3 = [Person personWithAge:24 withName:@"zhangsan" withCar:car1];
Person *p4 = [Person personWithAge:24 withName:@"lisi" withCar:car3];
Person *p5 = [Person personWithAge:20 withName:@"wangwu" withCar:car2];
    
//加入数组
NSArray *array = [NSArray arrayWithObjects:p1, p2, p3, p4, p5, nil];
    
//构建排序描述器
NSSortDescriptor *carNameDesc = [NSSortDescriptor sortDescriptorWithKey:@"car.name" ascending:YES];
NSSortDescriptor *personNameDesc = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
NSSortDescriptor *personAgeDesc = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:YES];
    
//把排序描述器放进数组里, 放入的顺序就是你想要排序的排序
//这里的排序是: 首先按照年龄排序, 然后是车的名字, 最后是按照人的名字
NSArray *descriptorArray = [NSArray arrayWithObjects:personAgeDesc, carNameDesc, personNameDesc, nil];
NSArray *sortedArray = [array sortedArrayUsingDescriptors:descriptorArray];
    
[sortedArray enumerateObjectsUsingBlock:^(Person *  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    NSLog(@"排序后的年龄: %d, 车的名字: %@, 名字: %@",obj.age, obj.car.name, obj.name);
}];
   
输出:
排序后的年龄: 20, 车的名字: Rolls-Royce, 名字: wangwu
排序后的年龄: 21, 车的名字: Audio, 名字: qianer
排序后的年龄: 23, 车的名字: Rolls-Royce, 名字: zhaoyi
排序后的年龄: 24, 车的名字: Audio, 名字: zhangsan
排序后的年龄: 24, 车的名字: BMW, 名字: lisi

从结果可以看出, 先按照age排序, 如果age相同; 按照car的名字排序; 如果car的名字相同, 再按照name排序;

原文:my.oschina.net/pengloo53/b…