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

时间:2017-06-28 18:20:41

标签: ios objective-c optimization nsarray

所以,我有一个排序NSArray,其中包含NSString个对象(从服务器下载),格式为: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. 查看今天是否在数组中(如果是,返回)
  2. 循环日期:

    2.1将dateString转换为date

    2.2比较date是否大于today =&gt;如果是,则返回

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

  4. 实际代码:

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

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

3 个答案:

答案 0 :(得分:3)

你的算法并不坏,虽然你的代码似乎没有实现它(没有排序?)。如果您想改进它,请考虑以下事项:

首先,在进行第一次扫描以检查完全匹配时可能没什么意义 - 这可能是通过无序数组进行线性搜索(由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为零,则您具有完全匹配,请将其返回

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

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

  5. 这是一次迭代,O(N),完全匹配的早期回报。

    HTH

答案 1 :(得分:0)

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

2017年6月28日星期三00:00:00

答案 2 :(得分:0)

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

我们可以使用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