对存放着字典的数组排序

其实是类似于给excel表格排序。NSArray里面有一些元素,这些元素都是NSDictionary,每个元素的keys都是一样的,想要对这样的数据来排序,可以使用到NSSortDescriptor

我先是看到NSHipster上的这篇文章,它是新构造一个类,每个key都是这个类的一个属性,使用如下代码来排序:


@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@property NSNumber *age;
@end

@implementation Person

- (NSString *)description {
    return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}

@end


NSArray *firstNames = @[ @"Alice", @"Bob", @"Charlie", @"Quentin" ];
NSArray *lastNames = @[ @"Smith", @"Jones", @"Smith", @"Alberts" ];
NSArray *ages = @[ @24, @27, @33, @31 ];

NSMutableArray *people = [NSMutableArray array];
[firstNames enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    Person *person = [[Person alloc] init];
    person.firstName = [firstNames objectAtIndex:idx];
    person.lastName = [lastNames objectAtIndex:idx];
    person.age = [ages objectAtIndex:idx];
    [people addObject:person];
}];

NSSortDescriptor *firstNameSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"firstName"
  ascending:YES
  selector:@selector(localizedStandardCompare:)];
NSSortDescriptor *lastNameSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"lastName"
  ascending:YES
  selector:@selector(localizedStandardCompare:)];
NSSortDescriptor *ageSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"age"
  ascending:NO];

NSLog(@"By age: %@", [people sortedArrayUsingDescriptors:@[ageSortDescriptor]]);
// "Charlie Smith", "Quentin Alberts", "Bob Jones", "Alice Smith"


NSLog(@"By first name: %@", [people sortedArrayUsingDescriptors:@[firstNameSortDescriptor]]);
// "Alice Smith", "Bob Jones", "Charlie Smith", "Quentin Alberts"


NSLog(@"By last name, first name: %@", [people sortedArrayUsingDescriptors:@[lastNameSortDescriptor, firstNameSortDescriptor]]);
// "Quentin Alberts", "Bob Jones", "Alice Smith", "Charlie Smith"

记得Java里面很多类都有toString()这个方法,觉得真是方便极了。而在objc中,相似的方法就是[xxx description],不过你可以重写这个方法,来达到你想要的效果。


上面这种把key当做一个类的属性的方法确实很好,但如果数据是从网上获取的,你事先不知道数据里的key都是一些什么,而runtime又不支持动态地为类添加成员变量。

这也让我苦恼了一小会儿,直到看到这篇文章

试想一下,你从网上获取一段JSON数据,它大概是像excel表格一样,你要根据里面的字段来对数据进行排序该如何做?

首先,把JSON数据转换成数组。
其次,数组里的都是一个个字典。那么就可以使用如下方法,来实现排序:

NSArray *people = @[
        @{@"surname":@"Simpson", @"given":@"Homer", @"title":@"Mr"},
        @{@"surname":@"Simpson", @"given":@"Marge", @"title":@"Mrs"},
        @{@"surname":@"Simpson", @"given":@"Bart", @"title":@"Mr"},
        @{@"surname":@"Simpson", @"given":@"Lisa", @"title":@"Miss"},
        @{@"surname":@"Simpson", @"given":@"Maggie", @"title":@"Miss"},
        @{@"surname":@"Flanders", @"given":@"Ned", @"title":@"Mr"}
        ];


NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"surname"  ascending:YES];
NSSortDescriptor *givenDescriptor = [[NSSortDescriptor alloc] initWithKey:@"given"  ascending:YES];
NSArray *sortDescriptors = @[nameDescriptor, givenDescriptor];

NSArray *ordered = [people sortedArrayUsingDescriptors:sortDescriptors];

NSSortDescriptor的一些方法

+ sortDescriptorWithKey:ascending:- initWithKey:ascending:这两个方法传入key,和排序方式(升序 or 降序)就能进行排序。如果你key对应的是NSString,那么就按照字符串排序【即@“123”是小于@“2”的】,如果key对应的是NSNumber,那么就按照数字排序。

+ sortDescriptorWithKey:ascending:selector:-initWithKey:ascending:selector:这两个方法可以让你自己指定用来排序的函数。

+ sortDescriptorWithKey:ascending:comparator:nitWithKey:ascending:comparator:可以让你自己来指定判断大小的方法。例如以下代码:


[[NSSortDescriptor alloc] initWithKey:colName ascending:asc comparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
            if ([obj1 floatValue] > [obj2 floatValue]){
                return (NSComparisonResult)NSOrderedDescending;
                
            }else if ([obj1 floatValue] < [obj2 floatValue]){
                return (NSComparisonResult)NSOrderedAscending;
            }
            else{
                return (NSComparisonResult)NSOrderedSame;
            }
            

参考

1.NSSortDescriptor

2.Sorting an array of Dictionaries

3.NSSortDescriptor reference