在字符串数组中查找最近的日期

Find nearest date in string array

所以,我有一个包含 NSString 对象(从服务器下载)的排序 NSArray,格式为:yyyy-MM-dd.

大致是这样的:

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"];

所以,今天是 2017-06-29,它不在数组中。我如何找到下一个最近的?在这个示例中是 06-30,但如果 06-30 不存在,它可能是 07-01...

更新

所以人们问我我试​​图做什么。所以是这样的(不是很有效,但是有效)

  1. 查找今天是否在数组中(如果是,return)
  2. 循环日期:

    2.1 将dateString转换为date

    2.2 比较 date 是否大于 today => return 如果是

  3. 如果在步骤#2 中未找到,return 日期数组中的最后一个对象。

实际代码:

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];

这看起来不太好,因为我可能会重新加载日期数组。我可以有更好的解决方案吗?

1。输入

所以你有一个 NSString 这样的数组

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

2。将 NSString 的数组转换为 NSDate

的数组

首先你需要将每个输入字符串转换成一个 NSDate

NSMutableArray<NSDate *> * dates = [NSMutableArray new];
NSDateFormatter * dateFormatter = [NSDateFormatter new];
dateFormatter.dateFormat = @"yyyy-MM-dd";
for (NSString * word in words) {
    [dates addObject:[dateFormatter dateFromString:word]];
}

3。找到 nearestDate

现在您可以找到最近的日期

NSDate * nearestDate = nil;
NSTimeInterval deltaForNearesttDate = 0;
NSDate * now = [NSDate new];
for (NSDate * date in dates) {
    NSTimeInterval delta = fabs([date timeIntervalSinceDate:now]);
    if (nearestDate == nil || (delta < deltaForNearesttDate)) {
        deltaForNearesttDate = delta;
        nearestDate = date;
    }
}

4。结论

结果进入nearestDate变量所以

NSLog(@"%@", nearestDate);

Wed Jun 28 00:00:00 2017

您的算法还不错,尽管您的代码似乎没有实现它(不是吗?)。如果您想改进它,请考虑:

首先,进行第一次扫描以检查精确匹配可能没有什么意义 - 这可能是通过无序数组的线性搜索(由 indexOfObject: 实现),如果失败,您必须再次扫描以寻找接近的匹配项,只需同时扫描即可。

其次,排序没有优势,最多为 O(NlogN),作为线性搜索,O(N) 会找到您需要的答案。

这是一个草图:

  1. 将您要搜索的日期从 NSString 转换为 NSDate,称其为 target
  2. bestMatchNSString 设置为 nil。将 bestDeltaNSTimeInterval 设置为最大可能值 DBL_MAX
  3. 迭代你的 dates 数组:

    3.1。将字符串日期转换为 NSDate,比如 date

    3.2。将 delta 设置为 datetarget

    之间的差值

    3.3。如果 delta 为零,则表示完全匹配,return 则

    3.4。如果 delta 优于 bestDelta,请更新 bestDeltabestMatch

  4. 迭代后 bestMatch 是最佳匹配,如果没有匹配则 nil

这是单次迭代,O(N),早 return 精确匹配。

HTH

请为您的问题找到最简单的解决方案。 更新了基于排序的解决方案!

我们可以使用NSPredicate Block来解决

    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]);

答案:最近日期:2017-06-30