How do I sort an NSMutableArray with custom objects in it?
我想做的似乎很简单,但我在网上找不到任何答案。我有一个
我认为这与这个方法有关:
1 | NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(???)]; |
在Java中,我将使我的对象实现可比性,或者使用内嵌的自定义比较器使用Copys.S排序……在Objto-C中,您究竟是如何做到这一点的?
比较法
为对象实现比较方法:
1 2 3 4 5 | - (NSComparisonResult)compare:(Person *)otherObject { return [self.birthDate compare:otherObject.birthDate]; } NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(compare:)]; |
nsSortDescriptor(更好)
或者通常更好:
1 2 3 4 | NSSortDescriptor *sortDescriptor; sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate" ascending:YES]; NSArray *sortedArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]]; |
通过向数组中添加多个键,可以轻松地按多个键排序。也可以使用定制的比较器方法。查看文档。
块(闪亮的!)由于Mac OS X 10.6和iOS 4,也有可能使用块进行排序:
1 2 3 4 5 6 | NSArray *sortedArray; sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { NSDate *first = [(Person*)a birthDate]; NSDate *second = [(Person*)b birthDate]; return [first compare:second]; }]; |
性能
一般来说,
见
您需要设置一个比较函数,该函数接受两个对象(类型为
这两个对象只是
此函数返回一个
这是一个粗糙的伪代码;您需要详细说明一个日期与另一个日期"更少"、"更多"或"相等"的含义(例如比较自epoch以来的秒数等):
1 2 3 4 5 6 7 8 | 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; } |
如果需要更紧凑的内容,可以使用三元运算符:
1 2 3 | NSComparisonResult compare(Person *firstPerson, Person *secondPerson, void *context) { return ([firstPerson birthDate] < [secondPerson birthDate]) ? NSOrderedAscending : ([firstPerson birthDate] > [secondPerson birthDate]) ? NSOrderedDescending : NSOrderedSame; } |
如果你经常这样做的话,内联可能会加快一点速度。
我在iOS 4中使用一个块完成了这个操作。必须将数组的元素从ID强制转换为类类型。在本例中,它是一个名为Score的类,具有名为Points的属性。
另外,如果数组元素的类型不正确,您需要决定要做什么,例如,我刚返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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:这是按降序排序。
从iOS 4开始,您还可以使用块进行排序。
对于这个特定的例子,我假设数组中的对象有一个"position"方法,它返回一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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]; |
注意:"排序"数组将自动释放。
我尽力了,但这对我很管用。在一个类中,我有另一个名为"EDOCX1"(29)的类,并希望按"EDOCX1"(29)的属性进行排序。
这就像一个魅力:
1 2 | NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:@"crimeScene.distance" ascending:YES]; [self.arrAnnotations sortUsingDescriptors:[NSArray arrayWithObject:sorter]]; |
格奥尔格·施有一个缺失的步骤吗?莱伊的第二个答案,但那就行了。
1 2 3 4 5 6 | NSSortDescriptor *sortDescriptor; sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate" ascending:YES] autorelease]; NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor]; NSArray *sortedArray; sortedArray = [drinkDetails sortedArrayUsingDescriptor:sortDescriptors]; |
1 2 3 4 5 | NSSortDescriptor *sortDescriptor; sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate" ascending:YES] autorelease]; NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor]; NSArray *sortedArray; sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors]; |
谢谢,它工作得很好…
你的
然后你会用
还有其他方法,但据我所知,
iOS 4块将为您节省:)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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介绍
对于
您可以使用以下通用方法。它应该能解决你的问题。
1 2 3 4 5 6 7 8 9 | //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]; |
如果您只是对一个
1 | [arrayToSort sortUsingSelector: @selector(compare:)]; |
这是因为数组中的对象(
下面是一些使用比较器块的示例代码。它对字典数组进行排序,其中每个字典在键"sort_key"中包含一个数字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #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; }]; |
上面的代码完成了为每个排序键获取一个整数值并对它们进行比较的工作,以说明如何执行该操作。由于
1 2 3 4 5 6 7 8 9 | #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行:
1 | return [[obj1 objectForKey: SORT_KEY] compare: [obj2 objectForKey: SORT_KEY]]; |
我倾向于使用简单的语句和大量临时变量,因为代码更容易阅读,也更容易调试。编译器无论如何都会优化掉临时变量,因此对于一线版本来说没有优势。
我刚刚完成了基于定制需求的多级排序。
//对值排序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | [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/multiplevelsortininginosobjectivec
我创建了一个小的类目方法库,称为LinqtoObjective,这使得这类事情更加容易。使用带有键选择器的排序方法,可以按
1 2 3 | NSArray* sortedByBirthDate = [input sort:^id(id person) { return [person birthDate]; }] |
我在我的一些项目中使用了SortUsingFunction:::
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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]; |
1 2 3 4 5 6 7 8 9 | -(NSMutableArray*) sortArray:(NSMutableArray *)toBeSorted { NSArray *sortedArray; sortedArray = [toBeSorted sortedArrayUsingComparator:^NSComparisonResult(id a, id b) { return [a compare:b]; }]; return [sortedArray mutableCopy]; } |
分类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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]; |
使用nscomparator排序
如果要对自定义对象进行排序,我们需要提供
1 2 3 | NSArray *sortedArray = [employeesArray sortedArrayUsingComparator:^NSComparisonResult(Employee *e1, Employee *e2){ return [e1.firstname compare:e2.firstname]; }]; |
使用nsSortDescriptor排序例如,假设我们有一个包含自定义类实例的数组,Employee具有firstname、lastname和age属性。下面的示例说明如何创建一个NSSortDescriptor,该描述符可用于按Age键以升序对数组内容进行排序。
1 2 3 | NSSortDescriptor *ageDescriptor = [[NSSortDescriptor alloc] initWithKey:@"age" ascending:YES]; NSArray *sortDescriptors = @[ageDescriptor]; NSArray *sortedArray = [employeesArray sortedArrayUsingDescriptors:sortDescriptors]; |
使用自定义比较进行排序名称是字符串,当排序要呈现给用户的字符串时,应始终使用本地化比较。通常,您还希望执行不区分大小写的比较。下面是一个带有(localizedStandardCompare:)的示例,用于按姓氏和名字对数组排序。
1 2 3 4 5 6 | 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/conceptive/sortdescriptors/articles/creating.htmlhttp://www.ios-blog.co.uk/tutorials/objective-c/how-to-sort-nsarray-with-custom-objects/
Swift的协议和函数编程使得这非常容易,您只需使类符合可比较的协议,实现协议所需的方法,然后使用sorted(by:)高阶函数创建排序数组,而不需要使用可变数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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) |
使用nsSortDescriptor使用自定义对象对nsmutableArray进行排序
1 2 3 4 | NSSortDescriptor *sortingDescriptor; sortingDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate" ascending:YES]; NSArray *sortArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]]; |
像这样用于嵌套对象,
1 2 | NSSortDescriptor * sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastRoute.to.lastname" ascending:YES selector:@selector(caseInsensitiveCompare:)]; NSMutableArray *sortedPackages = [[NSMutableArray alloc]initWithArray:[packages sortedArrayUsingDescriptors:@[sortDescriptor]]]; |
lastroute是一个对象,该对象保存to对象,该对象保存lastname字符串值。
在我的例子中,我使用"sortedarrayusingcomparator"对数组进行排序。请看下面的代码。
1 2 3 4 5 | 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]; }]; |
我的目标是,
1 2 3 4 5 6 | @interface ContactListData : JsonData @property(nonatomic,strong) NSString * contactName; @property(nonatomic,strong) NSString * contactSurname; @property(nonatomic,strong) NSString * contactPhoneNumber; @property(nonatomic) BOOL isSelected; @end |
swift中的排序数组
对于
1 2 3 4 5 6 | class User: NSObject { var id: String? var name: String? var email: String? var createdDate: Date? } |
现在我们有了一个数组,我们需要根据
1 2 3 4 5 6 7 8 9 10 11 12 13 | class User: NSObject { var id: String? var name: String? var email: String? var createdDate: Date? func checkForOrder(_ otherUser: User, _ order: ComparisonResult) -> Bool { if let myCreatedDate = self.createdDate, let othersCreatedDate = otherUser.createdDate { //This line will compare both date with the order that has been passed. return myCreatedDate.compare(othersCreatedDate) == order } return false } } |
现在让我们用一个
1 2 3 4 5 6 7 8 9 | extension Array where Element: User { //This method only takes an order type. i.e ComparisonResult.orderedAscending func sortUserByDate(_ order: ComparisonResult) -> [User] { let sortedArray = self.sorted { (user1, user2) -> Bool in return user1.checkForOrder(user2, order) } return sortedArray } } |
升序用法
1 | let sortedArray = someArray.sortUserByDate(.orderedAscending) |
降序用法
1 | let sortedArray = someArray.sortUserByDate(.orderedAscending) |
同一订单的使用
1 | let sortedArray = someArray.sortUserByDate(.orderedSame) |
Above method in
extension will only be accessible if theArray is of type
[User] ||Array
您必须创建SortDescriptor,然后可以使用下面的SortDescriptor对NSmutableArray进行排序。
1 2 3 | let sortDescriptor = NSSortDescriptor(key:"birthDate", ascending: true, selector: #selector(NSString.compare(_:))) let array = NSMutableArray(array: self.aryExist.sortedArray(using: [sortDescriptor])) print(array) |
1 2 | NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"_strPrice" ascending:sortFlag selector:@selector(localizedStandardCompare:)] ; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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(@"==============================="); |