Как мне отсортировать NSMutableArray с пользовательскими объектами в нем? - PullRequest
1234 голосов
/ 30 апреля 2009

То, что я хочу сделать, кажется довольно простым, но я не могу найти ответы в Интернете. У меня есть NSMutableArray объектов, и скажем, они являются объектами «Персона». Я хочу отсортировать NSMutableArray по Person.birthDate, который является NSDate.

Я думаю, что это как-то связано с этим методом:

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

В Java я бы заставил мой объект реализовать Comparable или использовал Collections.sort со встроенным пользовательским компаратором ... как же это сделать в Objective-C?

Ответы [ 26 ]

6 голосов
/ 16 апреля 2015

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

//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];
5 голосов
/ 06 декабря 2012

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

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

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

4 голосов
/ 06 марта 2013

Я создал небольшую библиотеку методов категорий, названную Linq to ObjectiveC , которая упрощает подобные вещи. Используя метод sort с ключевым селектором, вы можете сортировать по birthDate следующим образом:

NSArray* sortedByBirthDate = [input sort:^id(id person) {
    return [person birthDate];
}]
4 голосов
/ 09 мая 2011

Я использовал 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];
4 голосов
/ 04 июня 2013

Я только что сделал многоуровневую сортировку на основе пользовательских требований.

// сортировка значений

    [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

3 голосов
/ 10 января 2013
-(NSMutableArray*) sortArray:(NSMutableArray *)toBeSorted 
{
  NSArray *sortedArray;
  sortedArray = [toBeSorted sortedArrayUsingComparator:^NSComparisonResult(id a, id b) 
  {
    return [a compare:b];
 }];
 return [sortedArray mutableCopy];
}
3 голосов
/ 14 июня 2018

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

 NSSortDescriptor *sortingDescriptor;
 sortingDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
                                       ascending:YES];
 NSArray *sortArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]];
2 голосов
/ 06 сентября 2011

Сортировка 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];
1 голос
/ 28 марта 2017

Протоколы и функциональное программирование 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)
1 голос
/ 16 июня 2016

Сортировка с использованием NSComparator

Если мы хотим отсортировать пользовательские объекты, нам нужно предоставить NSComparator, который используется для сравнения пользовательских объектов. Блок возвращает значение NSComparisonResult для обозначения порядка двух объектов. Таким образом, для сортировки всего массива NSComparator используется следующим образом.

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

Сортировка с использованием NSSortDescriptor
Предположим, в качестве примера, что у нас есть массив, содержащий экземпляры пользовательского класса, у Employee есть атрибуты имя, фамилия и возраст. В следующем примере показано, как создать 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 / учебники / Objective-C / как к своего рода-NSArray-с-пользовательских-объектов /

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...