У меня есть массив из NSDate
объектов, и я хочу знать, сколько записей каждый месяц имеет, отныне через пять месяцев назад.Подсчитайте количество дат в массиве, которые выпадают в конкретный месяц
Это можно использовать, используя NSPredicate
?
У меня есть массив из NSDate
объектов, и я хочу знать, сколько записей каждый месяц имеет, отныне через пять месяцев назад.Подсчитайте количество дат в массиве, которые выпадают в конкретный месяц
Это можно использовать, используя NSPredicate
?
Несколько иной метод для Matthias's, хотя я не вижу никакого хорошего способа сделать это с помощью NSPredicate
либо, так как здесь требуется арифметика даты.
Это создает компоненты даты с каждой даты изначально и рассчитывает их с использованием NSCountedSet
. (Вы можете быть в состоянии использовать предикат на множестве подсчитывались.) Затем создается другой NSDateComponents
объект, описывающий месяц и год вы заинтересованы, и просто запросить набор с помощью countForObject:
NSArray * dates = @[/* Your dates here */];
NSCalendar * cal = [NSCalendar currentCalendar];
/* Convert the dates into date components objects for month and year. */
NSMutableArray * months = [NSMutableArray array];
for(NSDate * date in dates){
NSDateComponents * month = [cal components:(NSMonthCalendarUnit|NSYearCalendarUnit)
fromDate:date];
[months addObject:month];
}
/* Count the unique components. */
NSCountedSet * monthsCounts = [NSCountedSet setWithArray:months];
/* Use a predicate here on the set? */
/* A components object for month arithmetic. */
NSDateComponents * monthDelta = [NSDateComponents new];
/* Get month names for the current locale. */
NSDateFormatter * formatter = [NSDateFormatter new];
NSArray * monthNames = [formatter monthSymbols];
for(NSInteger i = 0; i > -NUM_MONTHS; i--){
/* Couting backwards from the current month, get a date components
* object for each month and year.
*/
[monthDelta setMonth:i];
NSDateComponents * currMonth;
currMonth = [cal components:(NSMonthCalendarUnit|NSYearCalendarUnit)
fromDate:[cal dateByAddingComponents:monthDelta
toDate:[NSDate date]
options:0]];
/* Get the count from the counted set and display. */
NSUInteger count = [monthsCounts countForObject:currMonth];
NSLog(@"%lu dates in %@", count,
[monthNames objectAtIndex:[currMonth month] - 1]);
}
Вы должны проверить даты в своем массиве 6 раз.
Во-первых: соответствие всем датам 1 июля и не позднее 1 августа.
Во-вторых: сопоставьте все даты 1 или 1 июня и до 1 июля.
В-третьих: сопоставьте все даты или после 1 мая и до 1 июня.
и т. Д.
В цикле вы создаете две даты. Первая дата - начало месяца в полночь. Вторая дата - ровно 1 месяц (!). Затем вы отфильтровываете все даты из массива, который включен или после первой и перед второй датой. В следующей итерации цикла вы делаете startDate на месяц раньше, чем предыдущий startDate.
Множество расчетных дат, но с помощью NSDateComponents это не имеет большого значения.
Поскольку я не знаю, как использовать NSPredicate с NSDates в массиве я использовал другой метод, но это в основном, как это работает:
NSDateComponents *oneMonthOffset = [[NSDateComponents alloc] init];
oneMonthOffset.month = 1;
NSDateComponents *thisMonth = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit fromDate:[NSDate date]];
thisMonth.day = 1;
NSDate *startOfCurrentMonth = [calendar dateFromComponents:thisMonth];
for (NSInteger offset = 0; offset > -5; offset--) {
NSDateComponents *startDateOffset = [[NSDateComponents alloc] init];
startDateOffset.month = offset;
NSDate *startDate = [calendar dateByAddingComponents:startDateOffset toDate:startOfCurrentMonth options:0];
NSDate *endDate = [calendar dateByAddingComponents:oneMonthOffset toDate:startDate options:0];
NSIndexSet *matchingIndexes = [array indexesOfObjectsPassingTest:^BOOL(NSDate *date, NSUInteger idx, BOOL *stop) {
if ([date compare:startDate] != NSOrderedAscending && [date compare:endDate] == NSOrderedAscending) {
// date is not before startDate (i.e. is on startDate or later than startDate) and date is before endDate
return YES;
}
return NO;
}];
NSLog(@"%d dates after %@ and before %@", [matchingIndexes count], [startDate descriptionWithLocale:[NSLocale currentLocale]], [endDate descriptionWithLocale:[NSLocale currentLocale]]);
}
Если массив дат очень большой вы могли бы хотите сначала отсортировать его и только просмотреть соответствующий диапазон. Этот код в настоящее время проверяет все NSDates в массиве.