2014-07-03 106 views
1

我不得不NSArrays:試圖優化一些循環代碼

  • _kundenArray - 持有所有客戶(目前約有3000)
  • _bestellungenMutArr - 持有所有訂單(目前約8000)

〜 ~~~~

EDIT2 - 補充說:

我的兩個陣列得到通過解析單獨的csv文件填充,所以最初我不知道客戶和訂單之間的任何關係。

~~~~~

爲每一位客戶我試圖確定它的訂單,更特別是其最後的順序(日期)。

我估計有一半以上的顧客沒有任何訂單,有的有幾個,有的很多。

一開始我有2個嵌套循環,外部遍歷所有客戶,內部遍歷所有訂單。其結果超過(3000 * 8000)比較(賦予附加的代碼)。

經過一番思考之後,我意識到我只有有效的訂單,即每個訂單都有一個客戶ID,並且對於每個客戶ID,我都有一個具有相同ID的現有客戶。 爲了減少內部循環的開銷,我根據客戶ID訂購了兩個數組。

這意味着第一個訂單對應於我的第一批客戶。例如:

  • _kundenArray [0]具有客戶ID爲
  • _bestellungenMutArr [0-3]已以便與IDS 24-27,通過每個客戶訂購

然後將每個相應的訂單收集到一個數組中,直到達到一個訂單,其客戶ID與我的客戶ID不符。然後退出(中斷)我的循環,從包含所有訂單(_bestellungenMutArr)的數組中刪除我收集的訂單,然後繼續處理下一個客戶。

從陣列中移除對象的速度非常快,因爲對象是ALL位於大數組的開頭。 (見圖表說明不同的數組操作here的性能在ridiculousfish

檢查儀器的時間簡檔數據,我發現的時候,超過99%都花在去除對象的儀器輸出: 然後我想出了利用enumerateObjectsUsingBlock的索引的想法,而不是使用內部循環的快速枚舉,我使用了塊枚舉器。爲了在內部循環中實現相同的開銷減少(即從不處理訂單兩次我跟蹤後續用於下一次迭代(對於下一個客戶)的偏移量的索引。這樣我規避了從數組中刪除對象,我認爲這可能是一個非常漂亮的想法。

檢查時間簡檔輸出原來它不是: enter image description here

因此,使用該變體通過使用removeObjectsInArray方法(約1500倍)從陣列的對象是快8倍左右,不是簡單地保持追蹤索引?

這是預計還是我錯過了什麼?

陣列移除/快速列舉的變體:

- (void) determineLastOrders 
{ 
    for (Kunde * kunde in _kundenArray) 
    { 
     NSMutableArray *bestellungenToRemove = [[NSMutableArray alloc] init]; 

     /* go through all (remaining) orders (after the loop the matching will be removed) and determine the next ones to remove */ 
     for (Bestellung * bestellung in _bestellungenMutArr) 
     { 
      if ([[bestellung bestKdNr] isEqualToString:kunde.kdnr]) 
      { 
       if (kunde.lastOrder == nil) 
       { 
        kunde.lastOrder = _orangeDate; //"init" 
       } 
       else if ([kunde.lastOrder compare:[bestellung bestDatum]] == NSOrderedAscending) 
       { 
        kunde.lastOrder = [bestellung bestDatum]; 
       } 
       //As this Bestellung already has had a date comparison (equal by kdnr) 
       //we won't need to visit it again by our next customer 
       [bestellungenToRemove addObject:bestellung]; 
      } 
      else 
      { //as all orders are ordered by the customer id we can abort iteration 
       //after we went past the current id 
       break; 
      } 
     } 
     [_bestellungenMutArr removeObjectsInArray: bestellungenToRemove]; 
    } 
} 

和檢查索引/塊枚舉變體:

- (void) determineLastOrders 
{ 
    __block NSUInteger bestIndex = 0; 
    for (Kunde * __block kunde in _kundenArray) 
    { 
     /* go through all (remaining) orders (after the loop the matching will be removed) and determine the next ones to remove */ 
     [_bestellungenMutArr enumerateObjectsUsingBlock: ^(Bestellung * bestellung, NSUInteger idx, BOOL *stop) 
     { 
      if (idx >= (bestIndex)) 
      { 
       if ([[bestellung bestKdNr] isEqualToString:kunde.kdnr]) 
       { 
        if (kunde.lastOrder == nil) 
        { 
         kunde.lastOrder = _orangeDate; //"init" 
        } 
        else if ([kunde.lastOrder compare:[bestellung bestDatum]] == NSOrderedAscending) 
        { 
         kunde.lastOrder = [bestellung bestDatum]; 
        }     
       } 
       else 
       { //as all orders are ordered by the customer id we can abort iteration 
        //after we went past the current id 
        bestIndex = idx+1; 
        *stop = YES; 
       } 
      } 
     }]; 
    } 
} 

提前感謝!

編輯:另一個問題剛剛出現在我的腦海裏。目前 - 在我的第一個代碼片段中,我總是在每個內部循環之後調用removeObjectsInArray方法。如果客戶沒有訂單,我刪除一個空數組(即試圖刪除零?)。 我的猜測是,如果傳遞一個空數組,那麼該方法退出的指令就是移除指令,因此比每個循環檢查內容的小數組效率更高。或者我錯了?

+0

爲什麼不使用NSDictionary來存儲特定客戶的訂單? NSDictionary的鍵值對可以是「kunde.kdnr-NSArray-Of-Orders」。這將允許一次獲得客戶的所有訂單,而不是迭代完整的數組訂單集。 – gagarwal

+1

如果這些數據在覈心數據中,查詢您要查找的內容會更容易。 –

+0

@gagarwall我解析兩個單獨的csv文件。一個包含所有客戶,另一個包含所有訂單。一開始我不知道哪個訂單對應哪個客戶。因此,無論哪種方式,我都必須通過兩者來確定關係。 –

回答

1

第二個例子比較好,但由於enumerateObjectsUsingBlock:...每次都從頭開始,所以您仍然通過更多的訂單來列舉每個客戶的訂單。 (與您的第一個代碼示例不同,您可以嘗試使用enumerateObjectsAtIndexes:...來代替傳入以從bestIndex開始的NSRange製作的索引集。

或者,你可以使用正常的循環:for (NSUInteger i = bestIndex; i < [_bestellungenMutArr count]; i++)這可能會更快。 optization的

+0

這真是太神奇了!使用正常循環時,該方法的時間消耗下降了11毫秒,比迄今爲止我的最佳解決方案快50倍以上。 非常感謝你! –

0

多了一個層次:

int count = [_bestellungenMutArr count]; 
for (NSUInteger i = bestIndex; i < count; i++) 

爲什麼呢?

現在每次都不會循環[_bestellungenMutArr計數]。