Search code examples
iosobjective-coptimizationnsarray

Find nearest date in string array


So, I've got an sorted NSArray that contains NSString object (downloaded from a server), with the format: yyyy-MM-dd.

It's pretty much like this:

NSArray <NSString *> *dates = @[@"2017-06-25",
                                @"2017-06-26",
                                @"2017-06-27",
                                @"2017-06-28",
                                @"2017-06-30",
                                @"2017-07-01",
                                @"2017-07-02",
                                @"2017-07-03"];

So, today is 2017-06-29, and it's not in the array. How do I get the next nearest one? In this sample is 06-30, but it might be 07-01 if 06-30 doesn't exist...

Update

So people are asking me about what I've attempted to do. So it's like this (not very effective, but work)

  1. Find if today is in the array (if yes, return)
  2. Loop dates:

    2.1 Convert dateString to date

    2.2 Compare if date is greater than today => return if YES

  3. If not found in step#2, return last object in dates array.

Actual code:

NSDateFormatter *formatter = [NSDateFormatter new];
formatter.dateFormat = @"yyyy-MM-dd";

NSDate *today = [NSDate date];
NSUInteger index = [dates indexOfObject:[formatter stringFromDate:today]];

// Step 1
if (index == NSNotFound) {

    // Step 2: Loop converted
    NSInteger i = 0;
    for (NSString *date in dates) {

        // Step2.1: find the next nearest date's index
        NSDate *convertedDate = [formmater dateFromString:date];

        // Step2.2: Compare
        if ([convertedDate intervalSinceDate:today] > 0) {
            index = i;
            break;
        }

        i++;
    }

    // Step 3: Still not found, index = last index
    if (index == NSNotFound) index = i-1;
}

return dates[index];

This doesn't look so good because I might reload the dates array pretty much. Can I have a better solution?


Solution

  • Please find the simplest solution for your problem. Updated solution based on sorting order!

    We can use NSPredicate Block to solve.

        static NSDateFormatter* formatter = nil;
        static NSDate* today = nil;
    
    
        // return an NSDate for a string given in yyyy-MM-dd
        - (NSDate *)dateFromString:(NSString *)string {
            if (formatter == nil) {
                formatter = [NSDateFormatter new];
                formatter.dateFormat = @"yyyy-MM-dd";
            }
            return [formatter dateFromString:string];
        }
    
        // Helps to return today date.
        -(NSDate*) getTodayDate {
            if (today == nil) {
                today = [NSDate date];
            }
            return today;
        }
    
                // Helps to find nearest date from Array using Predicate
        -(NSString*)findNearestDate:(NSArray*)dateArray {
            today = nil;
    
    
            NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(NSString *dateString, NSDictionary *bind){
                // this is the important part, lets get things in NSDate form so we can use them.
                NSDate *dob = [self dateFromString:dateString];
                NSComparisonResult result = [[self getTodayDate] compare:dob];
                if (result == NSOrderedSame || result == NSOrderedAscending) {
                    return true;
                }
                return false;
            }];
    
    
            // Apply the predicate block.
            NSArray *futureDates = [dateArray filteredArrayUsingPredicate:predicate];
            if ([futureDates count] > 0) {
                // Sort the Array.
                futureDates = [futureDates sortedArrayUsingSelector: @selector(compare:)];
                return [futureDates objectAtIndex:0];
            }
            return nil;
        }
    
        NSArray <NSString *> *dates = @[@"2017-06-25",
                                        @"2017-06-26",
                                        @"2017-06-27",
                                        @"2017-06-28",
                                        @"2017-06-30",
                                        @"2017-07-01",
                                        @"2017-07-02",
                                        @"2017-07-03"];
    
        NSLog(@"Nearest Date: %@", [self findNearestDate:dates]);
    

    Answer: Nearest Date: 2017-06-30