如何使用自定义对象对NSMutableArray进行排序?
-
03-07-2019 - |
题
我想做的事情似乎很简单,但我在网上找不到任何答案。我有一个NSMutableArray
对象,让我们说它们是'Person'对象。我想按NSDate
对Person.birthDate进行排序,这是一个<=>。
我认为这与此方法有关:
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]];
您可以通过向阵列添加多个键轻松地按多个键排序。也可以使用自定义比较器方法。请查看文档
块(闪亮!)从Mac OS X 10.6和iOS 4开始,还可以使用块进行排序:
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:
和基于块的方法比使用NSSortDescriptor
要快得多,因为后者依赖于KVC。 NSTableView
方法的主要优点是它提供了一种使用数据而不是代码来定义排序顺序的方法,这使得例如进行设置,以便用户可以通过单击标题行对<=>进行排序。
其他提示
请参阅NSMutableArray
方法 sortUsingFunction:context:
您需要设置一个比较函数,它接受两个对象(类型为Person
,因为您要比较两个NSComparisonResult
对象)和一个上下文参数。
这两个对象只是NSOrderedAscending
的实例。第三个对象是一个字符串,例如<!> @ QUOT;生日QUOT <!>;
此函数返回PersonA.birthDate
:如果PersonB.birthDate
<!> lt,则返回NSOrderedDescending
; NSOrderedSame
。如果<=> <!> gt;它将返回<=> <=>。最后,如果<=> == <=>,它将返回<=>。
这是粗糙的伪代码;你需要充实一个日期的含义<!>“少<!>”,<!>“更多<!>”;或<!>“;等于<!>”;到另一个日期(例如比较秒 - 自 - 纪元等):
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转换为我的类类型。 在这种情况下,它是一个名为Score的类,其中包含一个名为points的属性。
如果数组的元素不是正确的类型,你还需要决定该怎么做,对于这个例子我刚刚返回NSOrderedSame
,但是在我的代码中我虽然是例外。
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'方法,它返回一个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];
注意:<!> quot; sorted <!> quot;数组将被自动释放。
我尝试了所有,但这对我有用。在一个类中,我有另一个名为<!> quot; crimeScene
<!> quot;的类,并希望按<!>“; <=> <!>”的属性进行排序。
这就像一个魅力:
NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:@"crimeScene.distance" ascending:YES];
[self.arrAnnotations sortUsingDescriptors:[NSArray arrayWithObject:sorter]];
Georg Sch <!>#246; 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];
谢谢,它工作正常......
你的Person
对象需要实现一个方法,比如说compare:
带另一个NSComparisonResult
对象,然后根据两个对象之间的关系返回sortedArrayUsingSelector:
。
然后你会用@selector(compare:)
打电话给Comparable
,它应该完成。
还有其他方法,但据我所知,<=>接口没有Cocoa-equiv。使用<=>可能是最无痛的方法。
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
方法。它在不创建新实例的情况下对其进行排序。
您可以使用以下通用方法。它应该解决你的问题。
//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];
如果您只是对NSNumbers
数组进行排序,则可以使用1次调用对其进行排序:
[arrayToSort sortUsingSelector: @selector(compare:)];
这是有效的,因为数组中的对象(NSNumber
对象)实现了compare方法。您可以为NSString
对象执行相同的操作,甚至可以为实现比较方法的自定义数据对象数组执行相同的操作。
这是使用比较器块的一些示例代码。它对一组字典进行排序,其中每个字典都包含一个键<!> quot; 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;
}];
上面的代码完成了为每个排序键获取整数值并比较它们的工作,作为如何执行此操作的说明。由于<=>对象实现了比较方法,因此可以更简单地重写它:
#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]];
我倾向于选择简单的语句和许多临时变量,因为代码更容易阅读,更容易调试。编译器无论如何都会优化临时变量,因此对于一体化版本没有任何优势。
我创建了一个类别方法的小型库,名为 Linq to ObjectiveC ,这使得事情更容易。使用密钥选择器使用排序方法,您可以按以下方式按birthDate
排序:
NSArray* sortedByBirthDate = [input sort:^id(id person) {
return [person birthDate];
}]
我刚刚根据自定义要求进行了多级排序。
//对值进行排序
[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/美孚应用/ 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];
}
使用NSSortDescriptor为NSMutableArray排序自定义对象
NSSortDescriptor *sortingDescriptor;
sortingDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
ascending:YES];
NSArray *sortArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]];
排序NSMutableArray
非常简单:
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排序
如果我们想要对自定义对象进行排序,我们需要提供NSComparator
,用于比较自定义对象。该块返回NSComparisonResult
值以表示两个对象的排序。因此,为了对整个数组进行排序,<=>按以下方式使用。
NSArray *sortedArray = [employeesArray sortedArrayUsingComparator:^NSComparisonResult(Employee *e1, Employee *e2){
return [e1.firstname compare:e2.firstname];
}];
使用NSSortDescriptor排序
让<!>#8217; s假设我们有一个包含自定义类实例的数组,Employee具有属性firstname,lastname和age。以下示例说明如何创建可用于按年龄键按升序对数组内容进行排序的NSSortDescriptor。
NSSortDescriptor *ageDescriptor = [[NSSortDescriptor alloc] initWithKey:@"age" ascending:YES];
NSArray *sortDescriptors = @[ageDescriptor];
NSArray *sortedArray = [employeesArray sortedArrayUsingDescriptors:sortDescriptors];
使用自定义比较排序
名称是字符串,当您对字符串进行排序以呈现给用户时,您应始终使用本地化比较。通常,您还希望执行不区分大小写的比较。这里有一个示例(localizedStandardCompare :),按姓氏和名字排序数组。
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/
Swift的协议和函数式编程使您只需使类符合Comparable协议,实现协议所需的方法,然后使用sorted(by :)高阶函数创建一个排序数组顺便说一句,需要使用可变数组。
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)
就我而言,我使用<!> quot; sortedArrayUsingComparator <!> quot;排序数组。请看下面的代码。
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中排序数组
对于Swifty
以下人员是一种非常干净的技术,可以实现全球的上述目标。让我们有一个示例自定义类User
,它有一些属性。
class User: NSObject {
var id: String?
var name: String?
var email: String?
var createdDate: Date?
}
现在我们有一个数组,我们需要在createdDate
升序和/或降序的基础上进行排序。所以我们添加一个日期比较函数。
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
}
}
现在让extension
为Array
[User]
。简单来说,我们只为那些只有Array<User>
对象的Array添加一些方法。
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
}
}
升序用法
let sortedArray = someArray.sortUserByDate(.orderedAscending)
降序用法
let sortedArray = someArray.sortUserByDate(.orderedSame)
使用相同订单
<*>只有<=>属于类型时才能访问<=>中的上述方法 <=> || <=>
您必须创建sortDescriptor,然后您可以使用sortDescriptor对nsmutablearray进行排序。
let sortDescriptor = NSSortDescriptor(key: "birthDate", ascending: true, selector: #selector(NSString.compare(_:)))
let array = NSMutableArray(array: self.aryExist.sortedArray(using: [sortDescriptor]))
print(array)
对嵌套对象使用这样的方法,
NSSortDescriptor * sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastRoute.to.lastname" ascending:YES selector:@selector(caseInsensitiveCompare:)];
NSMutableArray *sortedPackages = [[NSMutableArray alloc]initWithArray:[packages sortedArrayUsingDescriptors:@[sortDescriptor]]];
lastRoute是一个对象,该对象保存to对象,对象保存lastname字符串值。
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"_strPrice"
ascending:sortFlag selector:@selector(localizedStandardCompare:)] ;
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(@"===============================");