iOS: сортировка массива NSDate по последнему году без учета года
У меня есть массив объектов NSDate. Эти объекты имеют годовую стоимость, но мне все равно. Я хочу отсортировать даты по самым последним, используя только месяц и день. Так, в июле, например, июньская дата будет около верхней части списка, а августовская дата будет около нижней, независимо от годов, содержащихся в этих объектах NSDate.
У меня проблемы с представлением способа сделать это. У кого-нибудь есть элегантное решение этой проблемы?
Спасибо!
РЕДАКТИРОВАТЬ: Очевидно, я не очень четко объяснил, что я ищу. Я хочу отсортировать массив так, чтобы самая последняя дата была первой, игнорируя год. Так, например, учитывая формат MM/dd/yy, если сегодня 06.05.14, и мой массив содержит эти даты:
01/04/14 04/05/14 21/07/14 30.12.14
Правильный порядок я хочу это:
04/05 01/04 30/30 07/21
3 ответа
Как указано здесь, вы можете получить компоненты даты NSDate и отсортировать их по этому значению.
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:[NSDate date]];
NSInteger day = [components day];
NSInteger month = [components month];
NSInteger year = [components year];
Вы можете игнорировать любые значения, которые вы хотели бы.
РЕДАКТИРОВАТЬ: Просто объединяя два ответа. Кредит Драйс за код сортировки.
NSArray* sortedArray = [yourArray sortedArrayUsingComparator:^NSComparisonResult(NSDate* lhs, NSDate* rhs)
{
NSDateComponents *lscomponents = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth fromDate:lhs];
NSDateComponents *rhcomponents = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth fromDate:rhs];
NSDateComponents *currentcomponents = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth fromDate:[NSDate date]];
NSInteger lday = [lscomponents day];
NSInteger lmonth = [lscomponents month];
NSInteger rday = [rhcomponents day];
NSInteger rmonth = [rhcomponents month];
if(lmonth < [currentcomponents month])
lmonth += 12;
else if(lmonth == [currentcomponents month])
{
if(lday < [currentcomponents day])
lmonth += 12;
}
if(rmonth < [currentcomponents month])
rmonth += 12;
else if(rmonth == [currentcomponents month])
{
if(rday < [currentcomponents day])
rmonth += 12;
}
int diff = lmonth - rmonth;
if (diff == 0)
diff = lday - rday;
if (diff < 0)
return NSOrderedDescending;
if (diff > 0)
return NSOrderedAscending;
return NSOrderedSame;
}];
Вы можете сделать это намного быстрее, кэшируя календарь.
EDIT2:
Я обновил сортировку, чтобы учесть ваши индивидуальные потребности. Если месяц и день раньше, вы добавляете 12 к месяцу. Затем сравните на основе нового псевдомесяца. Это должно дать вам обычай сортировки сегодня.
Вы можете написать собственную функцию сравнения, которая сортирует по месяцам и дням. использование sortedArrayUsingComparator
, например. Псевдокод (записанный из памяти, не скомпилированный и не опробованный):
NSArray* sortedArray = [yourArray sortedArrayUsingComparator:^NSComparisonResult(NSDate* lhs, NSDate* rhs)
{
// Use NSDateComponents to get the month and day from each date.
int diff = lhs.month - rhs.month;
if (diff == 0)
diff = lhs.day - rhs.day;
if (diff < 0)
return NSOrderedDescending;
if (diff > 0)
return NSOrderedAscending;
return NSOrderedSame;
}];
редактировать
Пример кода неполон, потому что NSdate
не имеет дневных или месячных методов. Вам нужно сначала пройти через несколько обручей, чтобы получить компоненты, см. NSDate get year / month / day. Извините, сейчас нет на Mac, поэтому я не могу попробовать.
NSDate* today = [NSDate date];
NSDate* left = <left side value>;
NSDate* right = <right side value>;
NSDateFormatter* dateFormatter = [NSDateFormatter new];
// Set time zone as desired
/* Skip this
** Get an NSDate for Dec 31 this year, so we can calc it's day-of-year. But note that it would probably suffice to just use the literal value 366 all the time.
[dateFormatter setDateFormat:@"yyyy"];
NSString* yearString = [dateFormatter stringFromDate:today];
NSString* dec31Dummy = [yearString stringByAppendingString:@"/12/31"];
[dateFormatter setDateFormat:@"yyyy/MM/dd"];
NSDate* dec31 = [dateFormatter dateFromString:dec31Dummy];
*/
// Date format for "day-of-year"
[dateFormatter setDateFormat:@"D"];
// Note that these are retrieving "day-of-year" values
NSString* todayString = [dateFormatter stringFromDate:today];
NSString* leftString = [dateFormatter stringFromDate:left];
NSString* rightString = [dateFormatter stringFromDate:right];
// NSString* dec31String = [dateFormatter stringFromDate:dec31];
// These convert the day-of-year values to numeric
int todayNum = [todayString intValue];
int leftNum = [leftString intValue];
int rightNum = [rightString intValue];
// int dec31Num = [dec31String intValue];
int dec31Num = 366;
// Adjust for dates that have already passed this year -- push them out into next year
If (leftNum < todayNum) leftNum += dec31Num;
if (rightNum < todayNum) rightNum += dec31Num;
int diff = leftNum - rightNum;
if (diff < 0) {
return NSOrderedDescending;
}
else if (diff > 0) {
return NSOrderedAscending;
}
else {
return NSOrderedSame;
}
Конечно, хотелось бы переместить инвариантную логику настройки из собственно компаратора.