如何在 NSArray 中使用多個排序條件來排序? - 海芋小站

相信如果你是 iOS 的程式設計師,一定都有使用過 NSArray 這個非常基本的元件,而大多數的程式設計師,在使用 NSArray 時,都會使用到排序的功能,而排序不外乎就是使用「sortedArrayUsingComparator」和「NSComparisonResult」的且合方式,但如果有多個條件要同時排序,這可就頭大了!幸好 iOS 提供了另一種陣列排序的方式,叫做「sortedArrayUsingDescriptors」,怎麼用呢?先別急,我們先看範例。

舉例來說,我們有一個物件,叫做「Person」,宣告如下:

@interface Person : NSObject @property (strong, nonatomic) NSString* name; @property (assign, nonatomic) int age; @property (assign, nonatomic) int income; @end

而接下來,我們分別宣告三個人,並把他們三個人加入陣列中,如下

Person *A = [[Person alloc] init]; A.name = @"孫無空"; A.age = 33; A.income = 50; Person *B = [[Person alloc] init]; B.name = @"唐三"; B.age = 43; B.income = 55; Person *C = [[Person alloc] init]; C.name = @"沙無淨"; C.age = 33; C.income = 60; NSMutableArray* unSortArray = [NSMutableArray arrayWithObjects:A,B,C, nil];

假設,我們要以「收入(income)」做為排序,收入愈高的排愈前面,怎麼排呢?很簡單,只要寫這樣~~

Person *A = [[Person alloc] init]; A.name = @"孫無空"; A.age = 33; A.income = 50; Person *B = [[Person alloc] init]; B.name = @"唐三"; B.age = 43; B.income = 55; Person *C = [[Person alloc] init]; C.name = @"沙無淨"; C.age = 33; C.income = 60; NSMutableArray* unSortArray = [NSMutableArray arrayWithObjects:A,B,C, nil]; NSComparator compare = ^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { NSString* strObj1 = (NSString*) obj1; NSString* strObj2 = (NSString*) obj2; NSNumber* number1 = @([strObj1 doubleValue]); NSNumber* number2 = @([strObj2 doubleValue]); return [number1 compare: number2]; }; NSMutableArray* arraySortCondtion = [[NSMutableArray alloc] init]; [arraySortCondtion addObject: [NSSortDescriptor sortDescriptorWithKey:@"sortcond_income" ascending:NO comparator: compare]]; NSArray* sortArray = [unSortArray sortedArrayUsingDescriptors: arraySortCondtion];

其中最重要的就是「sortedArrayUsingDescriptors」了,首先你要定義 Sort 的 Key,由於我們是依收入排序,所以我們定義「sortcond_income」;再來,由於我們是採用降冪排序,也就是收入高的在前面,所以在這裡「ascending」要設為 NO,最後就是你自己定義的 compare 函式了。

但是,代誌沒有你我想的這麼簡單,如果真的這樣排,會出錯,為什麼呢?因為在「Person」物件不認識「sortcond_income」這個 key 呀!所以我們要改寫一下 Person 物件,加入了「valueForUndefinedKey」。如此一來,當我們去抓 sortcond_income 時,就會把 income 轉成 NSString 來匯出了。

@implementation Person - (id)valueForUndefinedKey:(NSString *)key { if ([key isEqualToString:@"sortcond_income"]) { return [@(self.income) stringValue]; } return [super valueForUndefinedKey:key]; } @end

如果你依以上的排序方式實做一次,那麼最後的結果依序就是「沙無淨」、「唐三」、「孫無空」了。

但是,如果我們想要一次排多個條件呢?比如說這次採用「年齡升冪」排序,若是同樣的年齡,再採用「收入降冪」排序,那麼將如何寫呢?很簡單~~

Person *A = [[Person alloc] init]; A.name = @"孫無空"; A.age = 33; A.income = 50; Person *B = [[Person alloc] init]; B.name = @"唐三"; B.age = 43; B.income = 55; Person *C = [[Person alloc] init]; C.name = @"沙無淨"; C.age = 33; C.income = 60; NSMutableArray* unSortArray = [NSMutableArray arrayWithObjects:A,B,C, nil]; NSComparator compare = ^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { NSString* strObj1 = (NSString*) obj1; NSString* strObj2 = (NSString*) obj2; NSNumber* number1 = @([strObj1 doubleValue]); NSNumber* number2 = @([strObj2 doubleValue]); return [number1 compare: number2]; }; NSMutableArray* arraySortCondtion = [[NSMutableArray alloc] init]; [arraySortCondtion addObject: [NSSortDescriptor sortDescriptorWithKey:@"sortcond_age" ascending:YES comparator: compare]]; [arraySortCondtion addObject: [NSSortDescriptor sortDescriptorWithKey:@"sortcond_income" ascending:NO comparator: compare]]; NSArray* sortArray = [unSortArray sortedArrayUsingDescriptors: arraySortCondtion];

看到沒有,我們只不過多加了一行程式碼就完成了,而這行程式碼如下

[arraySortCondtion addObject: [NSSortDescriptor sortDescriptorWithKey:@"sortcond_age" ascending:YES comparator: compare]];

同樣的,一樣要在 Person 物件定義「sortcond_age」喔

@implementation Person - (id)valueForUndefinedKey:(NSString *)key { if ([key isEqualToString:@"sortcond_income"]) { return [@(self.income) stringValue]; } if ([key isEqualToString:@"sortcond_age"]) { return [@(_age) stringValue]; } return [super valueForUndefinedKey:key]; } @end

如果你依以上的排序方式實做一次,那麼最後的結果依序就是「沙無淨」、「孫無空」、「唐三」了。為什麼呢?因為「沙無淨」、「孫無空」的「年齡 (age) 」是一樣的,所以會依第二個條件「收入(income)」來做降冪排序,「沙無淨」的收入大於「孫無空」,所以自然就擺在「孫無空」 前面了,而可憐的「唐三」因為「年齡 (age) 」最大,所以被丟到最後面啦~~

以上就是 iOS 的陣列排序介紹,是以 Objective-C 做描述,讀者有興趣可以自行轉成 Swift,希望您使用起來能夠輕鬆愉快囉~