2011-10-01 59 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