2015-11-12 62 views
3

在面向iOS開發人員的採訪中,他們問我如何找到大型數組(> 100萬項)中刪除項目的最快解決方案,即:應用程序有從服務器的數組(我們不關心從服務器獲取此數組的方法)。然後,在服務器上,他們刪除了本地數組&中的幾個項目,我們不知道。那麼,我們如何才能在本地找到已刪除的項目,基於服務器&本地陣列上的新陣列? 我認爲在02天后&找到下面這個循環,但它只是當服務器刪除項目在開始或結束數組時。當在數組中間刪除項目時,此循環需要很長時間才能完成。iOS在大型數組中查找已刪除的項目(即:> 100萬項)

#define rchar (rand() % ('z'-'a') + 'a') 

- (無效)viewDidLoad中:

NSMutableArray * mar = [NSMutableArray new]; // represent server array. 



for (int i = 0; i<50000; i++) //10 50000 200000 400000 600000 800000 
{ 
    NSString * str = [NSString stringWithFormat:@"%c%c%c%c",rchar, rchar, rchar, rchar]; 
    [mar addObject:str]; 

} 

NSMutableArray *tmpServerArr = [[NSMutableArray alloc] initWithArray:mar copyItems:YES]; 

NSMutableArray *localArr = [[NSMutableArray alloc]initWithCapacity:50002]; // represent local array 
for (int i = 0; i<50002; i++) //10 50000 200000 
{ 
    switch (i) { 
     case 32111: [localArr addObject:[NSString stringWithFormat:@"%c%c%c%c",rchar, rchar, rchar, rchar]]; 

      break; 
      case 41234: [localArr addObject:[NSString stringWithFormat:@"%c%c%c%c",rchar, rchar, rchar, rchar]]; 
      break; 
     case 50000: [localArr addObject:mar[32111]]; 
      break; 
     case 50001: [localArr addObject:mar[41234]]; 
      break; 

     default: [localArr addObject:mar[i]]; 
      break; 
    } 

} 

NSUInteger localremainItem = [localArr count]; 

NSDate *start; 

NSUInteger loopWhile = 0; 
while (localremainItem > 0) { 
// while ([localArr count] > 0) { 


    NSUInteger idxItemStr = (localremainItem -1 - pow(-1, loopWhile)*(localremainItem-1))/2; // -1; 
    NSLog(@"idxstring: %li -- pow: %f", idxItemStr, pow(-1, loopWhile)); 
    NSString *itemStr = localArr[idxItemStr]; 
     NSLog(@"item checked : %@]", itemStr); 
     NSPredicate *pre = [ NSPredicate predicateWithFormat:@"NOT (SELF like %@)", itemStr]; 
    NSCountedSet * localCountedSet = [[ NSCountedSet alloc] initWithArray:localArr]; 
    NSCountedSet * serverCountedSet = [[ NSCountedSet alloc] initWithArray:tmpServerArr]; 

    if ([localCountedSet countForObject:itemStr] > [serverCountedSet countForObject:itemStr]) { 
     NSLog(@"this item %@ was deleted in server.", itemStr); 

    } 
    //else { 
     [localArr filterUsingPredicate: pre]; 
     [tmpServerArr filterUsingPredicate:pre]; 
     NSLog(@"localremain: %li", [localArr count]); 
     NSLog(@"tmpserverremain: %li", [tmpServerArr count]); 
    // } 

    if ([localArr count] == [tmpServerArr count]) { 
     localremainItem = 0; 
    } 
    else localremainItem = [localArr count]; 

     loopWhile +=1; 
} 

NSLog(@"now server arr is controled! time: %f", -[start timeIntervalSinceNow]); 

謝謝您的幫助。
**更新2015年11月14日:這個循環以下是8倍的速度:
在viewDidLoad中:

while ([localArr count] >0) { 

    NSUInteger maxRange =0; 
if ([localArr count] >500) { 
    maxRange = 500; 
}else maxRange = [localArr count]; 


    NSArray *sampleTest = [[NSArray alloc] initWithArray:[localArr subarrayWithRange:NSMakeRange(0,maxRange)]]; 
    NSLog(@"sampleTest cnt: %lu", (unsigned long)[sampleTest count]); 

if ([self countSampleTest:localArr serverArr:tmpServerArr sampleTest:sampleTest]) { 

    NSPredicate *pre = [ NSPredicate predicateWithFormat:@"NOT (SELF in %@)", sampleTest]; 
    [localArr filterUsingPredicate: pre]; 
    [tmpServerArr filterUsingPredicate:pre]; 
    NSLog(@"localremain: %li", [localArr count]); 
    NSLog(@"tmpserverremain: %li", [tmpServerArr count]); 
    } 
else { 
    NSLog(@"deleted item in here!: %i, %li", 0, [sampleTest count]); //[localArr count]/10); 
    int found = 0; 
    while (found <10) { 
     maxRange =0; 
     if ([localArr count] >50) { 
      maxRange = 50; 
     }else maxRange = [localArr count]; 


     NSArray *sampleTest1 = [[NSArray alloc] initWithArray:[localArr subarrayWithRange:NSMakeRange(0,maxRange)]]; 
     NSLog(@"sampleTest1 cnt: %lu", (unsigned long)[sampleTest1 count]); 
     if ([self countSampleTest:localArr serverArr:tmpServerArr sampleTest:sampleTest1]) { 


      NSPredicate *pre = [ NSPredicate predicateWithFormat:@"NOT (SELF in %@)", sampleTest1]; 
      [localArr filterUsingPredicate: pre]; 
      [tmpServerArr filterUsingPredicate:pre]; 
      NSLog(@"localremain: %li", [localArr count]); 
      NSLog(@"tmpserverremain: %li", [tmpServerArr count]); 
     } 
     else { 
      NSUInteger k = 0; 
      while (k< [sampleTest1 count]) { 

       NSLog(@"item checked %lu : %@]", (unsigned long)k, sampleTest1[k]); 
       NSCountedSet * localCountedSet = [[ NSCountedSet alloc] initWithArray:localArr]; 
       NSCountedSet * serverCountedSet = [[ NSCountedSet alloc] initWithArray:tmpServerArr]; 

       if ([localCountedSet countForObject:sampleTest1[k]] > [serverCountedSet countForObject:sampleTest1[k]]) { 
        NSLog(@"this item %@ was deleted in server.", sampleTest1[k]); 
       } 
       NSPredicate *pre = [ NSPredicate predicateWithFormat:@"NOT (SELF like %@)", sampleTest1[k]]; 
       [localArr filterUsingPredicate: pre]; 
       [tmpServerArr filterUsingPredicate:pre]; 
       NSLog(@"localremain: %li", [localArr count]); 
       NSLog(@"tmpserverremain: %li", [tmpServerArr count]); 
       if ([localArr count] == [tmpServerArr count]) { 
        k = [sampleTest1 count]; 
        found = 10; 
       }else k +=1; 
      } 
     } 
     found +=1; 
    } 
} 


    if ([localArr count] == [tmpServerArr count]) { 
     localArr = nil; 
    } 
    // if ([sampleTest count] == 0) { 
    //  localArr = nil; 
    // } 

} 

NSLog(@"this stuck is done!");//end viewDidLoad. 
-(BOOL)countSampleTest: (NSMutableArray *)localArr serverArr:(NSMutableArray *)tmpServerArr sampleTest:(NSArray *)sampleTest{ 
BOOL tf; 
int cntSampleLoc = 0; 
int cntSampleServer = 0; 

for (int i = 0 ; i < [sampleTest count]; i++) { 
    NSCountedSet * localCountedSet = [[ NSCountedSet alloc] initWithArray:localArr]; 
    NSCountedSet * serverCountedSet = [[ NSCountedSet alloc] initWithArray:tmpServerArr]; 
    cntSampleLoc += [localCountedSet countForObject:sampleTest[i]]; 
    //if (localArr[i] in tmpServerArr) { 
    cntSampleServer +=[serverCountedSet countForObject:sampleTest[i]]; 
    // } 
} 

if (cntSampleServer == cntSampleLoc) { 
    tf= true; 
}else tf = false; 
return tf;} 
+0

個人而言,我會告訴他們這是一個可怕的實現:)這似乎好得多沿增量比通整個數組或搜索數組。 –

+0

@MikeM:他們是老闆,我不能那樣告訴他們。多謝。 – Nik

+0

@Nik,你肯定*可以*和*應該*告訴別人,如果你可以備份它,實施是不好的,提供一個更好的選擇,並以專業的方式呈現你的發現。沒有人喜歡被告知他們錯了,但我相信很多人會喜歡有最好的工具。 –

回答

2

這使我首先想到的解決方案相當簡單:

NSArray *serverArray; 
NSMutableArray *localArray; 

// This will give you the difference. 
[localArray removeObjectsInArray:serverArray]; 

Docs說:

removeObjectsInArray:

這種方法類似於removeObject:,但它 讓你有效除去大量的對象集合與單個 操作。

+0

簡單不是最快的。問題是找到最快的解決方案。 – rmaddy

+0

@Rafal Sroka:我在[link](http://stackoverflow.com/questions/111866/best-way-to-remove-from-nsmutablearray-while-iterating)上閱讀了user1032657的評論,所以也許我會檢查你的稍後解決。很多tks。 – Nik

+0

@尼克,當然,請檢查其他解決方案並更新我們的研究結果。這是一個非常有趣的問題。 – RaffAl

1

你也可以我們NSSetNSMutableSet這將是更快的大型數據集:

NSMutableSet *serverSet = [NSMutableSet setWithArray: serverArray]; 
NSSet *localSet = [NSSet setWithArray: localArray]; 

[serverSet minusSet: localSet]; 

NSArray *deletedObjects = [serverSet allObjects]; 

this SO question有關詳情,請上NSArrayNSSet之間的性能差異。

+0

這個解決方案的小故障是將設置轉換爲數組會刪除重複項。設置課程不允許重複。 – RaffAl

+0

是的。但是,在搜索已刪除的項目時,這不應該成爲問題。順便說一句:你使用'removeObjectsInArray:'的答案也會刪除重複項。 – tilo

+0

@tilo:我測試了你的建議,當服務器刪除不重複的項目時它工作正常。很多tks。 – Nik

0

沒有求助於寫一個算法:分類

保持你的陣列是要幫助。

想象一下,在字典中尋找單詞「鼠標」。如果你從「a」開始,只檢查每個單詞是否是「鼠標」,它就會永遠佔用你的時間。但知道「m」字會在中間,而「o」在「m」的中間意味着你可以更快地找到你的字。

在一次採訪中,還有一個額外的好處,就是您知道如何在這個問題的範圍之外思考,寫作,並且讓您有機會展示您知道的其他內容。

+0

如果我們對數組進行排序,我們需要很多時間進行排序方法? – Nik

+0

如果您每次對數組進行排序(並取決於您使用的算法),** yes **。如果每次都在正確的位置插入新元素,則可以在'O(log n)'時間內完成條目和搜索(以及隨後的刪除)。 –

0
  1. 創建本地服務器陣列和服務器陣列的散列表(字典)。
  2. 循環遍歷本地數組,並查看是否存在於服務器數組中。

O(N + N + N)= O(3N)= 0(N)