如何sorting一个NSMutableArray中的自定义对象?

我想要做的事似乎很简单,但我无法在网上find任何答案。 我有一个NSMutableArray的对象,让我们说,他们是'人'的对象。 我想sortingNSMutableArray由Person.birthDate是一个NSDate

我认为这与这种方法有关:

 NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(???)]; 

在Java中,我会使我的对象实现Comparable,或使用Collections.sort与内联自定义比较器…你怎么在Objective-C中做到这一点?

比较方法

要么为你的对象实现一个比较方法:

 - (NSComparisonResult)compare:(Person *)otherObject { return [self.birthDate compare:otherObject.birthDate]; } NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(compare:)]; 

NSSortDescriptor(更好)

或者通常甚至更好:

 NSSortDescriptor *sortDescriptor; sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate" ascending:YES]; NSArray *sortedArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]]; 

您可以轻松地通过向数组添加多个键来sorting。 使用自定义比较器方法也是可能的。 看看文档 。

块(有光泽!)

自Mac OS X 10.6和iOS 4以来,还可以使用块进行sorting:

 NSArray *sortedArray; sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { NSDate *first = [(Person*)a birthDate]; NSDate *second = [(Person*)b birthDate]; return [first compare:second]; }]; 

性能

基于-compare:和block的方法通常要比使用NSSortDescriptor快得多,因为后者依赖于KVC。 NSSortDescriptor方法的主要优点是它提供了一种使用数据而不是代码来定义sorting顺序的方法,这使得用户可以通过点击标题行来sortingNSTableView

请参阅NSMutableArray方法sortUsingFunction:context:

您将需要设置一个比较函数,它使用两个对象( Persontypes,因为您正在比较两个Person对象)和一个上下文参数。

这两个对象只是Person实例。 第三个对象是一个string,例如@“birthDate”。

这个函数返回一个NSComparisonResult :如果PersonA.birthDate < PersonB.birthDate ,则返回PersonB.birthDate 。 如果PersonA.birthDate > PersonB.birthDate ,它将返回PersonB.birthDate 。 最后,如果PersonA.birthDate == PersonB.birthDate将返回PersonB.birthDate

这是粗略的伪代码; 你将需要充实一下date的意思是“更less”,“更多”或“相等”到另一个date(比如比较秒等等):

 NSComparisonResult compare(Person *firstPerson, Person *secondPerson, void *context) { if ([firstPerson birthDate] < [secondPerson birthDate]) return NSOrderedAscending; else if ([firstPerson birthDate] > [secondPerson birthDate]) return NSOrderedDescending; else return NSOrderedSame; } 

如果你想要更紧凑的东西,你可以使用三元运算符:

 NSComparisonResult compare(Person *firstPerson, Person *secondPerson, void *context) { return ([firstPerson birthDate] < [secondPerson birthDate]) ? NSOrderedAscending : ([firstPerson birthDate] > [secondPerson birthDate]) ? NSOrderedDescending : NSOrderedSame; } 

如果你这么做的话,内联可能会加速一点点。

我在iOS 4中使用了一个块。 必须将我的数组元素从id转换为我的类types。 在这种情况下,它是一个叫Score的类,有一个名为points的属性。

如果数组的元素不是正确的types,你也需要决定该怎么做,对于这个例子,我只是返回NSOrderedSame ,但是在我的代码中,我通过了一个exception。

 NSArray *sorted = [_scores sortedArrayUsingComparator:^(id obj1, id obj2){ if ([obj1 isKindOfClass:[Score class]] && [obj2 isKindOfClass:[Score class]]) { Score *s1 = obj1; Score *s2 = obj2; if (s1.points > s2.points) { return (NSComparisonResult)NSOrderedAscending; } else if (s1.points < s2.points) { return (NSComparisonResult)NSOrderedDescending; } } // TODO: default is the same? return (NSComparisonResult)NSOrderedSame; }]; return sorted; 

PS:这是降序sorting。

从iOS 4开始,您还可以使用块进行sorting。

对于这个特定的例子,我假设你的数组中的对象有一个'position'方法,它返回一个NSInteger

 NSArray *arrayToSort = where ever you get the array from... ; NSComparisonResult (^sortBlock)(id, id) = ^(id obj1, id obj2) { if ([obj1 position] > [obj2 position]) { return (NSComparisonResult)NSOrderedDescending; } if ([obj1 position] < [obj2 position]) { return (NSComparisonResult)NSOrderedAscending; } return (NSComparisonResult)NSOrderedSame; }; NSArray *sorted = [arrayToSort sortedArrayUsingComparator:sortBlock]; 

注意:“sorting”数组将被自动释放。

我尝试了所有,但是这为我工作。 在一个类中,我有另一个类名为“ crimeScene ”,并且想要通过“ crimeScene ”属性进行sorting。

这就像一个魅力:

 NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:@"crimeScene.distance" ascending:YES]; [self.arrAnnotations sortUsingDescriptors:[NSArray arrayWithObject:sorter]]; 

你的Person对象需要实现一个方法,比如compare:它接受另一个Person对象,并根据这两个对象之间的关系返回NSComparisonResult

然后你会调用sortedArrayUsingSelector:@selector(compare:) ,它应该完成。

还有其他的方法,但是据我所知, Comparable接口没有Cocoa-equiv。 使用sortedArrayUsingSelector:可能是最简单的方法。

GeorgSchölly的第二个答案有一个缺失的步骤,但是它的工作正常。

 NSSortDescriptor *sortDescriptor; sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate" ascending:YES] autorelease]; NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor]; NSArray *sortedArray; sortedArray = [drinkDetails sortedArrayUsingDescriptor:sortDescriptors]; 
 NSSortDescriptor *sortDescriptor; sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate" ascending:YES] autorelease]; NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor]; NSArray *sortedArray; sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors]; 

谢谢,它工作正常…

iOS 4块将为您节省:)

 featuresArray = [[unsortedFeaturesArray sortedArrayUsingComparator: ^(id a, id b) { DMSeatFeature *first = ( DMSeatFeature* ) a; DMSeatFeature *second = ( DMSeatFeature* ) b; if ( first.quality == second.quality ) return NSOrderedSame; else { if ( eSeatQualityGreen == m_seatQuality || eSeatQualityYellowGreen == m_seatQuality || eSeatQualityDefault == m_seatQuality ) { if ( first.quality < second.quality ) return NSOrderedAscending; else return NSOrderedDescending; } else // eSeatQualityRed || eSeatQualityYellow { if ( first.quality > second.quality ) return NSOrderedAscending; else return NSOrderedDescending; } } }] retain]; 

http://sokol8.blogspot.com/2011/04/sorting-nsarray-with-blocks.html一些描述;

对于NSMutableArray ,使用sortUsingSelector方法。 它sorting它,而不创build一个新的实例。

如果你只是sorting一个NSNumbers数组,你可以用1个呼叫进行sorting:

 [arrayToSort sortUsingSelector: @selector(compare:)]; 

这是因为数组中的对象( NSNumber对象)实现比较方法。 您可以为NSString对象做同样的事情,甚至可以为实现比较方法的自定义数据对象的数组。

以下是使用比较器块的一些示例代码。 它对字典数组进行sorting,每个字典在一个键“sort_key”中包含一个数字。

 #define SORT_KEY @\"sort_key\" [anArray sortUsingComparator: ^(id obj1, id obj2) { NSInteger value1 = [[obj1 objectForKey: SORT_KEY] intValue]; NSInteger value2 = [[obj2 objectForKey: SORT_KEY] intValue]; if (value1 > value2) { return (NSComparisonResult)NSOrderedDescending; } if (value1 < value2) { return (NSComparisonResult)NSOrderedAscending; } return (NSComparisonResult)NSOrderedSame; }]; 

上面的代码完成了为每个sorting键获取一个整数值并对它们进行比较的工作,以说明如何去做。 由于NSNumber对象实现了一个比较方法,因此可以更简单地进行重写:

  #define SORT_KEY @\"sort_key\" [anArray sortUsingComparator: ^(id obj1, id obj2) { NSNumber* key1 = [obj1 objectForKey: SORT_KEY]; NSNumber* key2 = [obj2 objectForKey: SORT_KEY]; return [key1 compare: key2]; }]; 

或者比较器的主体甚至可以被提取到1行:

  return [[obj1 objectForKey: SORT_KEY] compare: [obj2 objectForKey: SORT_KEY]]; 

我倾向于喜欢简单的语句和大量的临时variables,因为代码更容易阅读,并且更易于debugging。 编译器优化了临时variables,所以对于所有的一行版本来说没有任何优势。

我已经创build了一个类库方法的小库,称为Linq to ObjectiveC ,使这种事情更容易。 使用带有按键select器的sorting方法,您可以按照birthDate进行sorting,如下所示:

 NSArray* sortedByBirthDate = [input sort:^id(id person) { return [person birthDate]; }] 

我只是根据自定义要求进行多级分类。

//对值进行sorting

  [arrItem sortUsingComparator:^NSComparisonResult (id a, id b){ ItemDetail * itemA = (ItemDetail*)a; ItemDetail* itemB =(ItemDetail*)b; //item price are same if (itemA.m_price.m_selling== itemB.m_price.m_selling) { NSComparisonResult result= [itemA.m_itemName compare:itemB.m_itemName]; //if item names are same, then monogramminginfo has to come before the non monograme item if (result==NSOrderedSame) { if (itemA.m_monogrammingInfo) { return NSOrderedAscending; }else{ return NSOrderedDescending; } } return result; } //asscending order return itemA.m_price.m_selling > itemB.m_price.m_selling; }]; 

https://sites.google.com/site/greateindiaclub/mobil-apps/ios/multilevelsortinginiosobjectivec

我使用sortUsingFunction ::在我的一些项目中:

 int SortPlays(id a, id b, void* context) { Play* p1 = a; Play* p2 = b; if (p1.score<p2.score) return NSOrderedDescending; else if (p1.score>p2.score) return NSOrderedAscending; return NSOrderedSame; } ... [validPlays sortUsingFunction:SortPlays context:nil]; 
 -(NSMutableArray*) sortArray:(NSMutableArray *)toBeSorted { NSArray *sortedArray; sortedArray = [toBeSorted sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { return [a compare:b]; }]; return [sortedArray mutableCopy]; } 

您可以使用以下通用方法来达到您的目的。 它应该解决你的问题。

 //Called method -(NSMutableArray*)sortArrayList:(NSMutableArray*)arrDeviceList filterKeyName:(NSString*)sortKeyName ascending:(BOOL)isAscending{ NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:sortKeyName ascending:isAscending]; [arrDeviceList sortUsingDescriptors:[NSArray arrayWithObject:sorter]]; return arrDeviceList; } //Calling method [self sortArrayList:arrSomeList filterKeyName:@"anything like date,name etc" ascending:YES]; 

sortingNSMutableArray非常简单:

 NSMutableArray *arrayToFilter = [[NSMutableArray arrayWithObjects:@"Photoshop", @"Flex", @"AIR", @"Flash", @"Acrobat", nil] autorelease]; NSMutableArray *productsToRemove = [[NSMutableArray array] autorelease]; for (NSString *products in arrayToFilter) { if (fliterText && [products rangeOfString:fliterText options:NSLiteralSearch|NSCaseInsensitiveSearch].length == 0) [productsToRemove addObject:products]; } [arrayToFilter removeObjectsInArray:productsToRemove]; 
 NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"_strPrice" ascending:sortFlag selector:@selector(localizedStandardCompare:)] ; 

使用NSComparator进行sorting

如果我们想sorting自定义对象,我们需要提供NSComparator ,它用来比较自定义对象。 该块返回一个NSComparisonResult值来表示这两个对象的sorting。 所以为了sorting整个数组NSComparator以下面的方式使用。

 NSArray *sortedArray = [employeesArray sortedArrayUsingComparator:^NSComparisonResult(Employee *e1, Employee *e2){ return [e1.firstname compare:e2.firstname]; }]; 

使用NSSortDescriptor进行sorting
作为一个例子,假设我们有一个包含自定义类的实例的数组,Employee有属性firstname,lastname和age。 下面的例子说明了如何创build一个NSSortDescriptor,它可以用年龄键以升序对数组内容进行sorting。

 NSSortDescriptor *ageDescriptor = [[NSSortDescriptor alloc] initWithKey:@"age" ascending:YES]; NSArray *sortDescriptors = @[ageDescriptor]; NSArray *sortedArray = [employeesArray sortedArrayUsingDescriptors:sortDescriptors]; 

使用自定义比较进行sorting
名称是string,并且当您对string进行sorting以呈现给用户时,您应该始终使用本地化的比较。 通常你也希望执行不区分大小写的比较。 这里有一个例子(localizedStandardCompare :),用last和first命名数组。

 NSSortDescriptor *lastNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastName" ascending:YES selector:@selector(localizedStandardCompare:)]; NSSortDescriptor * firstNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"firstName" ascending:YES selector:@selector(localizedStandardCompare:)]; NSArray *sortDescriptors = @[lastNameDescriptor, firstNameDescriptor]; NSArray *sortedArray = [employeesArray sortedArrayUsingDescriptors:sortDescriptors]; 

有关参考和详细讨论,请参阅: https : //developer.apple.com/library/ios/documentation/Cocoa/Conceptual/SortDescriptors/Articles/Creating.html
http://www.ios-blog.co.uk/tutorials/objective-c/how-to-sort-nsarray-with-custom-objects/

在我的情况下,我使用“sortedArrayUsingComparator”sorting数组。 看下面的代码。

 contactArray = [[NSArray arrayWithArray:[contactSet allObjects]] sortedArrayUsingComparator:^NSComparisonResult(ContactListData *obj1, ContactListData *obj2) { NSString *obj1Str = [NSString stringWithFormat:@"%@ %@",obj1.contactName,obj1.contactSurname]; NSString *obj2Str = [NSString stringWithFormat:@"%@ %@",obj2.contactName,obj2.contactSurname]; return [obj1Str compare:obj2Str]; }]; 

另外我的对象是,

  @interface ContactListData : JsonData @property(nonatomic,strong) NSString * contactName; @property(nonatomic,strong) NSString * contactSurname; @property(nonatomic,strong) NSString * contactPhoneNumber; @property(nonatomic) BOOL isSelected; @end 

Swift的协议和函数式编程使得这很简单,只需要让类符合Comparable协议,实现协议所需的方法,然后使用sorting后的(by:)高阶函数创build一个sorting的数组而不需要使用顺便说一下可变数组。

 class Person: Comparable { var birthDate: NSDate? let name: String init(name: String) { self.name = name } static func ==(lhs: Person, rhs: Person) -> Bool { return lhs.birthDate === rhs.birthDate || lhs.birthDate?.compare(rhs.birthDate as! Date) == .orderedSame } static func <(lhs: Person, rhs: Person) -> Bool { return lhs.birthDate?.compare(rhs.birthDate as! Date) == .orderedAscending } static func >(lhs: Person, rhs: Person) -> Bool { return lhs.birthDate?.compare(rhs.birthDate as! Date) == .orderedDescending } } let p1 = Person(name: "Sasha") p1.birthDate = NSDate() let p2 = Person(name: "James") p2.birthDate = NSDate()//he is older by miliseconds if p1 == p2 { print("they are the same") //they are not } let persons = [p1, p2] //sort the array based on who is older let sortedPersons = persons.sorted(by: {$0 > $1}) //print sasha which is p1 print(persons.first?.name) //print James which is the "older" print(sortedPersons.first?.name) 
 NSMutableArray *stockHoldingCompanies = [NSMutableArray arrayWithObjects:fortune1stock,fortune2stock,fortune3stock,fortune4stock,fortune5stock,fortune6stock , nil]; NSSortDescriptor *sortOrder = [NSSortDescriptor sortDescriptorWithKey:@"companyName" ascending:NO]; [stockHoldingCompanies sortUsingDescriptors:[NSArray arrayWithObject:sortOrder]]; NSEnumerator *enumerator = [stockHoldingCompanies objectEnumerator]; ForeignStockHolding *stockHoldingCompany; NSLog(@"Fortune 6 companies sorted by Company Name"); while (stockHoldingCompany = [enumerator nextObject]) { NSLog(@"==============================="); NSLog(@"CompanyName:%@",stockHoldingCompany.companyName); NSLog(@"Purchase Share Price:%.2f",stockHoldingCompany.purchaseSharePrice); NSLog(@"Current Share Price: %.2f",stockHoldingCompany.currentSharePrice); NSLog(@"Number of Shares: %i",stockHoldingCompany.numberOfShares); NSLog(@"Cost in Dollars: %.2f",[stockHoldingCompany costInDollars]); NSLog(@"Value in Dollars : %.2f",[stockHoldingCompany valueInDollars]); } NSLog(@"===============================");