在字符串数组中查找最近的日期
Posted
技术标签:
【中文标题】在字符串数组中查找最近的日期【英文标题】:Find nearest date in string array 【发布时间】:2017-06-28 18:20:41 【问题描述】:所以,我有一个已排序的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...
更新
所以人们都在问我我试图做什么。所以就是这样(不是很有效,但是工作)
-
查找今天是否在数组中(如果是,则返回)
循环日期:
2.1 将dateString
转换为date
2.2 比较date
是否大于today
=>如果是则返回
如果在第 2 步中没有找到,则返回日期数组中的最后一个对象。
实际代码:
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];
这看起来不太好,因为我可能会重新加载日期数组。我能有更好的解决方案吗?
【问题讨论】:
到目前为止你尝试过什么?请添加您的代码。一种简单的方法是遍历数组并计算两个日期之间的时间。存储差异最小的日期。当然,如果您知道列表是预先排序的,那么您可以进行明显的优化(忽略检查日期之前的任何日期,并忽略除检查日期之后差异最小的日期之外的任何日期)。NSDateFormatter
至少将日期转换为NSDate
。那么,您到底在寻找什么?未来最接近?过去最接近?最接近什么?你有什么尝试?
@RoboticCat 我不知道如何找到它。在我的代码中,我只是检查是否找到了今天。数组已排序。你认为我必须将整个数组转换为NSDate
,今天添加,再次排序然后找到最近的吗?
@Larme 要求查找下一个最近的,即未来
@Eddie 定义“更好”的答案。只是因为它循环了两次,所以在你看来它“更慢”。伙计,为您的代码降低一些指标。查看内存和时间使用情况,然后回过头来说明为什么您的解决方案或其他解决方案更糟。下面列出的答案很好,可以完成工作。
【参考方案1】:
您的算法还不错,尽管您的代码似乎没有实现它(没有排序?)。如果您想改进它,请考虑:
首先进行第一次扫描以检查精确匹配可能没有什么意义 - 这可能是通过无序数组进行的线性搜索(由indexOfObject:
实现),如果失败,您必须再次扫描近距离比赛,同时进行。
其次排序没有优势,充其量是O(NlogN),作为线性搜索,O(N)会找到你需要的答案。
这是一个草图:
-
将您要搜索的日期从
NSString
转换为NSDate
,称之为target
将bestMatch
、NSString
设置为nil
。将bestDelta
、NSTimeInterval
设置为最大可能值DBL_MAX
。
遍历您的 dates
数组:
3.1。将字符串日期转换为NSDate
,比如date
3.2。将delta
设置为date
和target
之间的差异
3.3。如果delta
为零,则表示完全匹配,返回它
3.4。如果delta
优于bestDelta
,则更新bestDelta
和bestMatch
迭代后bestMatch
是最佳匹配,如果没有则nil
。
这是一个单次迭代,O(N),提前返回完全匹配。
HTH
【讨论】:
检查更新的算法。看来我的和你的一样。我已经更新它以匹配我下面的代码。 您仍在对阵列进行两次传递。您现在已经声明数组已排序,因此可以对上述算法进行简单改进,以便在找到超过目标日期的日期后终止。所以这两种算法并不相同,但在实践中差异可能很小。 所以,你的意思是我应该删除indexOfObject:
并执行循环?
请参阅答案中的步骤 3.3。并且您引入的先决条件是数组已排序,步骤 3.4 不再需要跟踪最佳增量,第一个 +ve 增量是最好的,这也意味着这两个步骤可以简单地组合......此外正在排序的数组允许将线性迭代替换为 二分搜索,从而将复杂性降低到 O(logN) - 但是这样的更改只值得数组很大并且可能在您的情况下过度杀伤,尽管我现在看到您无论如何都选择了更复杂的解决方案,所以可能不会!希望这次探索对您有所帮助。
取决于您对复杂的定义;-) 一个使用谓词(内存分配)、一个块(以及更多)、创建一个辅助数组(甚至更多)等;另外两个是提前退出的简单循环。无论如何,您已经欣赏了许多答案和讨论,这很好!保持好奇的心态,它会为您服务。【参考方案2】:
请为您的问题找到最简单的解决方案。 更新了基于排序顺序的解决方案!
我们可以使用 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
【讨论】:
既然可以得到 dateInterval 并与 0 比较,为什么还要使用 compare? 我在谓词中使用 NSComparisonResult。它将帮助我们找到订单。 我认为我们可以像这样使用日期比较并且工作几乎相同:return [[self getDateToday] intervalSinceDate:dob] >= 0;
另外,如果我们使用 [dateArray indexOfObjectPassingTest:]
块谓词会不会更好?
是的 >= 等于结果 == NSOrderedSame ||结果 == NSOrderedAscending。
请找到更新的答案,您将在排序日期方面为您提供帮助。【参考方案3】:
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
变量so
NSLog(@"%@", nearestDate);
2017 年 6 月 28 日星期三 00:00:00
【讨论】:
这看起来比我的解决方案差得多:|你必须循环两次才能找到,而我的只有一次(甚至可能没有完全循环) @Eddie 你问过How do I get the next nearest one?
。然后你用你自己的代码更新了你的问题。那你到底在问什么?比您的循环更少的解决方案?
对不起,有人要我的代码,所以我添加了它们。是的,你的回答完成了工作。但是你能想到另一个比我更好的吗?我在为这个问题寻求一个好的解决方案
@Eddie:我认为indexOfObject:
也有一个循环(它会迭代直到找到对象)。所以你实际上也做了 2 个循环。以上是关于在字符串数组中查找最近的日期的主要内容,如果未能解决你的问题,请参考以下文章