我正在制作一个电视指南应用程序,并且我正在尝试使用NSDictionary来获取NSArray中最接近的3个日期。到目前为止一切都那么好,但我一直试图弄清楚如何使用尽可能少的内存和尽可能少的代码(因此减少错误或崩溃的可能性)以最佳方式执行此操作。该数组已经排序。
我有一本包含所有频道节目的词典,为期一天。字典包含一个NSDate(称为日期) 让我们说一个频道有8个节目,时间现在是11:45。 show#3从11:00开始,到12:00结束,show#4从12:00开始,到13:00结束,#13出现在13:00到14:00等。 我怎么能从我的字典数组中获取show#3 (以前开始的!),#4和#5最快(内存方面)最简单?
目前我正在进行for循环获取每个字典,然后将字典日期与当前日期进行比较。那就是我被困住的地方。或者也许我只是有一个大脑fag。
我目前的代码(经过一段时间测试不同的东西):
- (NSArray*)getCommingProgramsFromDict:(NSArray*)programs amountOfShows:(int)shows
{
int fetched = 0;
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSDate *latestDate = [NSDate date];
for (NSDictionary *program in programs)
{
NSDate *startDate = [program objectForKey:@"date"];
NSLog(@"Program: %@", program);
switch ([latestDate compare:startDate]) {
case NSOrderedAscending:
NSLog(@"latestDate is older, meaning the show starts in the future from latestDate");
// do something
break;
case NSOrderedSame:
NSLog(@"latestDate is the same as startDate");
// do something
break;
case NSOrderedDescending:
NSLog(@"latestDate is more recent, meaning show starts in the past");
// do something
break;
}
// Now what?
}
return resultArray;
}
我正在使用ARC为iOS 5编写它。
答案 0 :(得分:1)
这个问题要求“最快(记忆明智)”。您是否正在寻找最快或最具记忆力/足迹的人?对于算法,通常会有空格与时间的权衡,因此当您加快速度时,通常会通过添加索引和其他查找数据结构来增加内存占用量。
对于这个问题,直接实现将迭代通过每个通道,每个项目将每个通道与内存中保存的前3个进行比较。但那可能很慢。
使用额外的存储空间,你可以有一个额外的阵列,它可以编入时间段(每15分钟一个粒度就足够了吗?),然后菊花链显示这些时隙。根据当前时间,您可以直接索引到当前时段,然后查找下一组节目。该数组将具有指向字典指向的相同对象的指针。这是一种额外的数据结构,可以优化一种特定的访问模式,但它可以节省成本 - 更多内存。
这会增加你的足迹,但会非常快,因为它只是一个数组索引偏移量。
最后,您可以将所有节目存储在sqlite数据库或CoreData中,并使用一个查询解决您的问题。让sql引擎做的努力。这也将使你的记忆足迹合理。
希望能引发一些想法。
编辑:
一个粗略的例子,展示了如何构建一个外观表 - 一个每15分钟有一个插槽的数组。它是瞬间跳转到当前时隙,因为它只是一个数组偏移。然后你走了绝对的步行数 - 接下来的三个你就走了。所以,它是一个3次迭代的数组偏移量。
大多数代码都是建立日期 - 查找表,查找时间段和循环是微不足道的。
NSInteger slotFromTime(NSDate *date)
{
NSLog(@"date: %@", date);
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:(NSHourCalendarUnit | NSMinuteCalendarUnit) fromDate:date];
NSInteger hour = [dateComponents hour];
NSInteger minute = [dateComponents minute];
NSInteger slot = (hour * 60 + minute)/15;
NSLog(@"slot: %d", (int)slot);
return slot;
}
int main (int argc, const char * argv[])
{
// An array of arrays - the outer array is an index of 15 min time slots.
NSArray *slots[96];
NSDate *currentTime = [NSDate date];
NSInteger currentSlot = slotFromTime(currentTime);
// populate with shows into the next few slots for demo purpose
NSInteger index = currentSlot;
NSArray *shows1 = [NSArray arrayWithObjects:@"Seinfeld", @"Tonight Show", nil];
slots[++index] = shows1;
NSArray *shows2 = [NSArray arrayWithObjects:@"Friends", @"Jurassic Park", nil];
slots[++index] = shows2;
// find next three -jump directly to the current slot and only iterate till we find three.
// we don't have to iterate over the full data set of shows
NSMutableArray *nextShow = [[NSMutableArray alloc] init];
for (NSInteger currIndex = currentSlot; currIndex < 96; currIndex++)
{
NSArray *shows = slots[currIndex];
if (shows)
{
for (NSString *show in shows)
{
NSLog(@"found show: %@", show);
[nextShow addObject:show];
if ([nextShow count] == 3)
break;
}
}
if ([nextShow count] == 3)
break;
}
return 0;
}
输出:
2011-10-01 17:48:10.526 Craplet[946:707] date: 2011-10-01 21:48:10 +0000
2011-10-01 17:48:10.527 Craplet[946:707] slot: 71
2011-10-01 17:48:14.335 Craplet[946:707] found show: Seinfeld
2011-10-01 17:48:14.336 Craplet[946:707] found show: Tonight Show
2011-10-01 17:48:21.335 Craplet[946:707] found show: Friends
答案 1 :(得分:1)
我不确定我是否理解你的模型结构,你有一个NSArray
个节目,每个节目都是NSDictionary
持有节目的NSDate以及其他信息,对吗?
然后,一个想法是根据节目开始时间与现在之间的距离对节目NSArray
进行排序。
NSArray* shows = ... // your arraw of NSDictionaries representing each show
NSArray* sortedShows = [shows sortedArrayUsingComparator:^(id show1, id show2) {
NSTimeInterval ti1 = fabs([[show1 objectForKey:@"startDate"] timeIntervalSinceNow]);
NSTimeInterval ti2 = fabs([[show2 objectForKey:@"startDate"] timeIntervalSinceNow]);
return (NSComparisonResult)(ti1-ti2);
}];
当然,在这一点上很容易只采用sortedShows
数组的3个第一个节目。
如果我误解了您的模型结构,请编辑您的问题以指定它,但我确信您可以调整我的代码以适应您的模型
答案 2 :(得分:1)
在您的编辑和解释之后,这是另一个答案,希望更好地适合您的问题。
想法是找到下一个节目的索引(现在是startDate)。一旦你拥有它,很容易在上一个索引(播出时)和后面的2个节目上获得节目。
NSUInteger indexOfNextShow = [arrayOfShows indexOfObjectPassingTest:^BOOL(id program, NSUInteger idx, BOOL *stop) {
NSDate* startDate = [program objectForKey:@"date"];
return ([startDate timeIntervalSinceNow] > 0); // startDate after now, so we are after the on-air show
}];
在该阶段,indexOfNextShow
包含NSArray
中将在当前节目播出后播放的节目索引。因此,根据您的问题,您想要的是索引为indexOfNextShow-1
(在空中展示),indexOfNextShow
(下一个节目)和indexOfNextShow+1
(在下一个节目后显示)的对象。
// in practice you should check the range validity before doing this
NSIndexSet* indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(indexOfNextShow-1,3)];
NSArray* onAirShowAnd2Next = [arrayOfShows objectsAtIndexes:indexes];
显然,在实际操作中,您应该尝试添加一些验证(例如indexOfNextShow
为&gt; 0,然后尝试访问索引为indexOfNextShow-1
的对象,而indexOfNextShow+1
未超过您的展示总数数组)。
这样做的好处是,由于你的节目数组已经由startDate排序,indexOfObjectPassingTest:
返回通过测试的第一个对象,并在找到正确的对象后立即停止迭代。所以这是简洁,易于阅读的代码和相对有效的。