Сортировка NSArray строк или объектов даты

86

У меня NSArrayесть строка даты (например, NSString) например: «Thu, 21 May 09 19:10:09 -0700»

Мне нужно отсортировать NSArrayпо дате. Я NSDateсначала подумал о преобразовании строки даты в объект, но застрял на том, как сортировать по NSDateобъекту.

Спасибо.

почтовая служба14
источник
С пометкой помечено, поскольку это относится к платформе Foundation, а не только к iPhone.
Куинн Тейлор

Ответы:

110

Сохраните даты как NSDateобъекты в массиве NS (Mutable), затем используйте -[NSArray sortedArrayUsingSelector:или -[NSMutableArray sortUsingSelector:]и передайте @selector(compare:)в качестве параметра. -[NSDate compare:]Метод заказа даты в возрастающем порядке для вас. Это проще, чем создавать NSSortDescriptor, и намного проще, чем писать собственную функцию сравнения. ( NSDateобъекты знают, как сравнивать себя друг с другом, по крайней мере настолько эффективно, насколько мы могли надеяться достичь с помощью специального кода.)

Куинн Тейлор
источник
11
Неясно, был ли исходный вопрос о сортировке массива дат или сортировке массива объектов, имеющих поле даты. Это самый простой подход, если это первый вариант, но если второй, то NSSortDescriptor - лучший вариант.
smorgan
@smorgan, как NSSortDescriptor обрабатывает нулевые даты?
Ash
Спасибо за вашу помощь, я думаю, мы должны прочитать больше в Apple Docs, но это кажется таким скучным, пока вы не воспользуетесь им.
Abo3atef
1
Не могли бы вы показать это в фрагменте кода в качестве примера? Заранее спасибо.
uplearnedu.com
115

Если у меня есть несколько NSMutableArrayобъектов с полем типа beginDate, NSDateя использую, NSSortDescriptorкак показано ниже:

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"beginDate" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
Винзенцвебер
источник
3
Я знаю, что прошло много времени (когда был принят предыдущий ответ, NSSortDescriptor еще не могло быть), но для будущего использования этот ответ должен быть правильным.
Vive
1
Это отличное решение. решил мою проблему в нескольких строках кода. Спасибо за тонну @vinzenzweber
Pratyusha Terli
1
На самом деле ... Я был шокирован, что это сработало при первом запуске! Я думал, что initWithKey был зарезервирован для словарей, в которых определен ключ, но все, что вам нужно сделать, это указать свойство в массиве объектов? Пусть светит винзенцвеберскавичский свет !!
whyoz
NSSortDescriptor существует с OS X 10.3, в конце 2003 года. Это немного другой сценарий, в котором дата является полем в другом объекте. С еще более современным API вы можете использовать -[NSMutableArray sortUsingComparator:](10.6+) и передать блок, который возвращает результат вызова -compare:двух полей. Вероятно, это будет быстрее, чем вызов -valueForKey:каждого объекта. Вы даже можете использовать -sortWithOptions:usingComparator:и передавать параметры для одновременной сортировки.
Куинн Тейлор
как вышеуказанный NSSortDescriptor обрабатывает нулевые даты? Нужно ли указывать дескриптору, что с ними делать, если да, то как?
Ash
17

Вы также можете использовать что-то вроде следующего:

//Sort the array of items by  date
    [self.items sortUsingComparator:^NSComparisonResult(id obj1, id obj2){
        return [obj2.date compare:obj1.date];
    }];

Но это предполагает, что дата хранится NSDateскорее как aNString , что не должно вызывать проблем. Я рекомендую также хранить данные в необработанном формате. Облегчает манипулирование в подобных ситуациях.

TheCodingArt
источник
9

Вы можете использовать блоки для сортировки на месте:

sortedDatesArray = [[unsortedDatesArray sortedArrayUsingComparator: ^(id a, id b) {
    NSDate *d1 = [NSDate dateWithString: s1];
    NSDate *d2 = [NSDate dateWithString: s2];
    return [d1 compare: d2];
}];

Я предлагаю вам преобразовать все ваши строки в даты перед сортировкой, чтобы не выполнять преобразование больше раз, чем есть элементы даты. Любой алгоритм сортировки даст вам больше преобразований строки в дату, чем количество элементов в массиве (иногда значительно больше)

еще немного о сортировке блоков: http://sokol8.blogspot.com/2011/04/sorting-nsarray-with-blocks.html

Константин Соколинский
источник
Это вариант той же неоптимальной идеи, представленной @notoop. В любом случае, сначала нужно перейти на NSDate.
Куинн Тейлор
По сути, он просто поместил мой ответ с ответом @ notoop ... совершенно необязательно, чтобы дважды публиковать их, если вы спросите меня ...
TheCodingArt
Это намного медленнее, чем синтаксический анализ строк даты в массив NSDate, а затем сортировка массива NSDate, потому что будет 2 * (n - 1) раз больше синтаксического анализа строки. Синтаксический анализ строк обычно является тяжелой работой для процессора.
CarlLee
5

В моем случае это сработало следующим образом:

    NSArray * aUnsorted = [dataToDb allKeys];
    NSArray * arrKeys = [aUnsorted sortedArrayUsingComparator: ^ NSComparisonResult (id obj1, id obj2) {
        NSDateFormatter * df = [[NSDateFormatter alloc] init];
        [df setDateFormat: @ "дд-ММ-гггг"];
        NSDate * d1 = [df dateFromString: (NSString *) obj1];
        NSDate * d2 = [df dateFromString: (NSString *) obj2];
        return [d1 compare: d2];
    }];

У меня был словарь, где все ключи где даты в формате dd-MM-yyyy. AllKeys возвращает ключи словаря без сортировки, и я хотел представить данные в хронологическом порядке.

Хавьер Калатрава Ллаверия
источник
5

Вы можете использовать sortedArrayUsingFunction:context:. Вот пример:

NSComparisonResult dateSort(NSString *s1, NSString *s2, void *context) {
    NSDate *d1 = [NSDate dateWithString:s1];
    NSDate *d2 = [NSDate dateWithString:s2];
    return [d1 compare:d2];
}

NSArray *sorted = [unsorted sortedArrayUsingFunction:dateSort context:nil];

При NSMutableArrayиспользовании sortArrayUsingFunction:context:вместо него вы можете использовать .

notnoop
источник
9
Это плохая идея - функция сравнения должна быть быстрой и не должна создавать объекты NSDate из строк для каждого сравнения. Если вы уже используете - [NSDate compare:], просто сохраните даты в массиве и используйте -sortedArrayUsingSelector: напрямую.
Куинн Тейлор
Я думаю, что это хорошее решение, если вы сортируете объекты, у которых уже есть поле NSDate. Нет?
GnarlyDog
1
Если массив уже содержит NSDateобъекты, вы можете использовать мой ответ выше или даже использовать -[NSMutableArray sortUsingComparator:], который был добавлен в 10.6.
Куинн Тейлор
Если вы используете массив словаря, в котором есть объект "ключ-значение" для даты как NSString вместе с некоторыми другими объектами "ключ-значение", то это решение пока является лучшим. Просто нужно немного изменить функцию dateSort. Пальцы вверх! :)
Erfan
4

Когда у вас есть NSDate, вы можете создать с NSSortDescriptorпомощью, initWithKey:ascending:а затем использовать его sortedArrayUsingDescriptors:для сортировки.

Сморган
источник
Этот подход будет работать, но использование -sortedArrayUsingSelector: немного проще и не требует создания дополнительного объекта.
Куинн Тейлор,
Перед редактированием в вопросе упоминался «ключ даты», поэтому я предположил, что это действительно был массив объектов / словарей, которые имели дату как одно поле, а не массив необработанных дат. В этом случае sortedArrayUsingSelector: более сложен, поскольку требует написания специальной процедуры сортировки для выполнения поиска.
smorgan
Да, извините за путаницу - я убрал эту ссылку, так как он просто говорил, что хранит свой массив с ключом «дата», и я понял, что это только усложняет вопрос. Вы определенно правы насчет относительной сложности, учитывая более сложную структуру данных.
Куинн Тейлор
2

Swift 3.0

myMutableArray = myMutableArray.sorted(by: { $0.date.compare($1.date) == ComparisonResult.orderedAscending })
Абхишек Джайн
источник
1

Изменить это

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"beginDate" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];

Чтобы

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"Date" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];

Просто поменяйте КЛЮЧ: он должен быть Dateвсегда

user2339385
источник