0

オブジェクトの配列がありNSDate、今から 5 か月前までの各月のエントリ数を知りたいです。

を使用してこれを行うことは可能NSPredicateですか?

4

2 に答える 2

2

NSPredicateMatthias の方法とは多少異なりますが、ここでは日付演算が必要なため、これを行う良い方法はわかりません。

これにより、最初に各日付から日付コンポーネントが作成され、 を使用してそれらがカウントされ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]);
}
于 2013-07-24T21:15:54.087 に答える
1

配列内の日付を 6 回テストする必要があります。

最初: 7 月 1 日以降かつ 8 月 1 日より前のすべての日付に一致します。
2 番目: 6 月 1 日以降かつ 7 月 1 日より前のすべての日付に一致します。
3 番目: 5 月 1 日以降かつ 6 月 1 日より前のすべての日付に一致します。
等々

ループで 2 つの日付を作成します。最初の日付は、月の初めの午前 0 時です。2回目のデートはちょうど1ヶ月後(!)。次に、最初の日付以降で 2 番目の日付より前のすべての日付を配列から除外します。ループの次の反復では、startDate を前の startDate より 1 か月早くします。

日付の計算がたくさんありますが、NSDateComponents の助けを借りれば大したことではありません。

配列内の NSDates で NSPredicate を使用する方法がわからないため、別の方法を使用しましたが、基本的には次のように機能します。

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 をテストします。

于 2013-07-24T16:43:37.697 に答える