2011-10-01 60 views
1

我正在制作电视指南应用程序,并试图从NSArray和NSDictionary中获取最近的3个日期。到目前为止这么好,但我一直在试图弄清楚如何使用尽可能少的内存和尽可能少的代码(从而减少错误或崩溃的可能性)这样做的最佳方式。数组已经排序。从列表中挑选最近的3个日期

我有一本包含所有频道节目一天的字典。该字典隐藏了一个NSDate(称为日期)。
可以说一个频道有8个节目,现在时间是11:45。展会#3从11:00开始,到12:00结束,#4从12:00开始到13:00结束,#5在13:00到14:00之间展示。
我怎样才能取得节目#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; 
} 

我写它的iOS 5,采用ARC。

回答

1

您的编辑和解释之后,这里是另一个答案,希望更好地解决你的问题。

这个想法是找到下一个节目的索引(现在的startDate)。一旦拥有了它,将很容易在上一个索引(在播出)和之后的两个节目中播放节目。

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幸福> 0试图索引indexOfNextShow-1而不是过去显示的是在阵列中的总数indexOfNextShow+1访问对象之前)。

这样做的好处是,由于您的数组显示已按startDate排序,因此indexOfObjectPassingTest:会返回通过测试的第一个对象,并在找到正确的对象时立即停止迭代。因此,这既简洁,易于阅读的代码,也相对高效。

+0

这似乎是正确的,我也试过它..但似乎iOS5(ARC)不喜欢它。我得到'BOOL(^)(__ strong id,NSUInteger,BOOL *)'[3]''类型的参数'void(^)(__ strong id,NSUInteger,BOOL *)'的不兼容块指针类型发送错误消息'''还有,我的理解是否正确,你错过了'];'在最后? –

+0

我删除了我的其他评论,这对我也不起作用。 。 –

+0

对不起,没有测试我的代码,你对错过的']'是正确的,另一个问题与iOS5或ARC无关。问题是我的块没有返回值(我忘了'return YES'语句),所以编译器断言该块返回'void',而它期望一个返回'BOOL'的块(根据'indexOfObjectPassingTest:'方法签名)。我刚编辑我的代码来解决这些问题,在同一时间简化块('indexOfObjectPassingTest'自动停止在第一个匹配,所以我是不确定在该方法的情况下需要“* stop”) – AliSoftware

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 
+0

感谢您的回复。我认为你写的第二个选项适合我(尽管我还没有完全理解它)。 SQL lite选项不会很好,因为应用程序(当前)确实使用核心数据。它从外部服务获取数据并将其保存在内存中。第一个是我想到的那个,但没有看到它那么好(因此很慢)。你能否给我一个关于#2的意思的小代码例子,以便我正确理解你的意思? –

+0

当然 - 给我一分钟 – bryanmac

+0

太棒了!现在我明白你的意思了。凉。我会试一试! –

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个第一节目。

如果我误解你的模型结构,请编辑您的问题指定它,但我敢肯定,你能适应我的代码,以适应你的模型,然后

+0

谢谢!我想你没有理解我,所以我更新了我的问题。该数组已按照节目的开始顺序排序。我需要的是目前正在播出的节目+下两个节目。所以,如果现在的时间是11:45,那么我喜欢从11:00到12:00开始的节目结果+接下来的两场节目。 –

+0

好了然后我写了另一个答案(因为它是一个完全不同的解决方案,我认为它比编辑我的原始答案更好),希望更好地回答你的问题 – AliSoftware

+0

我相信这仍然会迭代整个数据集。最快的算法会直接跳到当前的时隙索引,并且只重复3次以找到接下来的三个。 – bryanmac