我不得不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的索引的想法,而不是使用內部循環的快速枚舉,我使用了塊枚舉器。爲了在內部循環中實現相同的開銷減少(即從不處理訂單兩次我跟蹤後續用於下一次迭代(對於下一個客戶)的偏移量的索引。這樣我規避了從數組中刪除對象,我認爲這可能是一個非常漂亮的想法。
檢查時間簡檔輸出原來它不是:
因此,使用該變體通過使用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方法。如果客戶沒有訂單,我刪除一個空數組(即試圖刪除零?)。 我的猜測是,如果傳遞一個空數組,那麼該方法退出的指令就是移除指令,因此比每個循環檢查內容的小數組效率更高。或者我錯了?
爲什麼不使用NSDictionary來存儲特定客戶的訂單? NSDictionary的鍵值對可以是「kunde.kdnr-NSArray-Of-Orders」。這將允許一次獲得客戶的所有訂單,而不是迭代完整的數組訂單集。 – gagarwal
如果這些數據在覈心數據中,查詢您要查找的內容會更容易。 –
@gagarwall我解析兩個單獨的csv文件。一個包含所有客戶,另一個包含所有訂單。一開始我不知道哪個訂單對應哪個客戶。因此,無論哪種方式,我都必須通過兩者來確定關係。 –