Как отсортировать NSMutableArray с пользовательскими объектами в нем?

То, что я хочу сделать, кажется довольно простым, но я не могу найти ответы в Интернете. У меня есть NSMutableArray объектов, и, допустим, это объекты Person. Я хочу сортировать NSMutableArray по 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]]; по 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: и block-based будут в целом более NSSortDescriptor , чем использование NSSortDescriptor поскольку последний полагается на KVC. Основное преимущество метода NSSortDescriptor заключается в том, что он предоставляет способ определения вашего порядка сортировки с использованием данных, а не кода, что упрощает, например, настраивать вещи, чтобы пользователи могли сортировать NSTableView , щелкая по строке заголовка.

См. Метод sortUsingFunction:context:

Вам нужно будет настроить функцию сравнения, которая принимает два объекта (типа Person , поскольку вы сравниваете два объекта Person ) и параметр контекста .

Эти два объекта являются только экземплярами Person . Третий объект – это строка, например @ “birthDate”.

Эта функция возвращает NSComparisonResult : она возвращает NSOrderedAscending если PersonA.birthDate < PersonB.birthDate . Он вернет NSOrderedDescending если PersonA.birthDate > PersonB.birthDate . Наконец, он вернет NSOrderedSame если PersonA.birthDate == PersonB.birthDate .

Это грубый псевдокод; вам нужно будет определить, что означает для одной даты «меньше», «больше» или «равно» другой дате (например, сравнение секунд-с-эпохи и т. д.):

 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 до моего типа classа. В этом случае это class под названием «Оценка» со свойством, называемым точками.

Также вам нужно решить, что делать, если элементы вашего массива не соответствуют типу, для этого примера я только что вернулся 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]; 

Примечание: «отсортированный» массив будет автореализован.

Я пробовал все, но это сработало для меня. В classе у меня есть еще один class под названием « crimeScene » и хочу сортировать по свойству « crimeScene ».

Это работает как шарм:

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

Во втором ответе Георга Шёлли есть недостающий шаг, но он отлично работает.

 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: который принимает другой объект Person , и возвращает NSComparisonResult соответствии с отношением между двумя объектами.

Затем вы должны вызвать sortedArrayUsingSelector: с @selector(compare:) и это должно быть сделано.

Есть и другие способы, но, насколько я знаю, не существует Cocoa-equiv интерфейса Comparable . Использование sortedArrayUsingSelector: это, вероятно, самый безболезненный способ сделать это.

Блоки 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 . Он сортирует это место, не создавая новый экземпляр.

Если вы просто сортируете массив NSNumbers , вы можете отсортировать их с помощью 1 вызова:

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

Это работает, потому что объекты в массиве (объекты NSNumber ) реализуют метод сравнения. Вы можете сделать то же самое для объектов NSString или даже для массива пользовательских объектов данных, реализующих метод сравнения.

Вот пример кода с использованием блоков компаратора. Он сортирует массив словарей, где каждый словарь содержит число в ключе «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; }]; 

В приведенном выше коде рассматривается работа по получению целочисленного значения для каждого ключа сортировки и их сравнение в качестве иллюстрации того, как это сделать. Поскольку объекты 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]]; 

Я предпочитаю простые утверждения и множество временных переменных, потому что код легче читать и проще отлаживать. Компилятор в любом случае оптимизирует временные переменные, поэтому нет преимущества для версии «все в одной строке».

Вы можете использовать следующий общий метод для своей цели. Он должен решить вашу проблему.

 //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]; 

Я создал небольшую библиотеку категорийных методов, называемую 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/mobil-apps/ios/multilevelsortinginiosobjectivec

Я использовал sortUsingFunction :: в некоторых моих проектах:

 int SortPlays(id a, id b, void* context) { Play* p1 = a; Play* p2 = b; if (p1.scorep2.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]; } 

Сортировка 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 для обозначения порядка двух объектов. Поэтому для сортировки всего массива NSComparator используется следующим образом.

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

Сортировка с использованием NSSortDescriptor
Предположим в качестве примера, что у нас есть массив, содержащий экземпляры пользовательского classа, 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 и функциональное программирование очень упрощают вам просто сделать свой class совместимым с протоколом Comparable, реализовать методы, требуемые протоколом, а затем использовать отсортированную (по:) функцию высокого порядка для создания отсортированного массива без необходимости использования Кстати, изменчивые массивы.

 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) 

В моем случае я использую «sortedArrayUsingComparator» для сортировки массива. Посмотрите на приведенный ниже код.

 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 Person ниже – очень чистая техника для достижения вышеуказанной цели для всего мира. Позволяет иметь пример пользовательского classа 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 . Простыми словами можно добавить некоторые методы только для тех массивов, в которых есть только объекты User .

 extension Array where Element: User { //This method only takes an order type. ie 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(.orderedAscending) 

Использование для того же порядка

 let sortedArray = someArray.sortUserByDate(.orderedSame) 

Вышеуказанный метод в extension будет доступен только в том случае, если Array имеет тип [User] || Array

Вам нужно создать sortDescriptor, а затем вы можете отсортировать nsmutablearray с помощью sortDescriptor, как показано ниже.

  let sortDescriptor = NSSortDescriptor(key: "birthDate", ascending: true, selector: #selector(NSString.compare(_:))) let array = NSMutableArray(array: self.aryExist.sortedArray(using: [sortDescriptor])) print(array) 

Вы используете NSSortDescriptor для сортировки NSMutableArray с настраиваемыми объектами

  NSSortDescriptor *sortingDescriptor; sortingDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate" ascending:YES]; NSArray *sortArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]]; по  NSSortDescriptor *sortingDescriptor; sortingDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate" ascending:YES]; NSArray *sortArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]]; 
 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(@"==============================="); 
  • Как отсортировать NSMutableArray с помощью sortedArrayUsingDescriptors?
  • Порядок Mysql по определенным значениям идентификатора
  • Как использовать std :: sort для сортировки массива в C ++
  • Лучший способ сделать сортировку WPF ListView / GridView при нажатии на заголовок столбца?
  • Сортировка строк в таблице данных
  • как сортировать строку как число в datagridview в winforms
  • Почему мой цикл сортировки, кажется, добавляет элемент, где он не должен?
  • Есть ли поддержка в C ++ / STL для сортировки объектов по атрибуту?
  • Сохранение заказа с помощью LINQ
  • Пересечение двух отсортированных массивов
  • Существует ли алгоритм сортировки по целому числу O (n)?
  • Давайте будем гением компьютера.