我必须使用NSArrays:
~~~~~
EDIT2 - 补充道:
我的数组都通过解析单独的csv文件来填充,所以最初我不知道客户和订单之间的任何关系。
~~~~~
对于每个客户,我都会尝试确定其订单,更具体地说是最后一个订单(日期)。
我估计超过一半的客户没有订单,有些订单有几个,其他订单很多。
一开始我有2个嵌套循环,外部循环遍历所有客户,内部循环遍历所有订单。最终进行了超过(3000 * 8000)次比较(赋予附加代码)。
经过一番思考后,我意识到我只有有效的订单,即每个订单都有客户ID,而对于每个客户ID,我都有一个具有相同ID的现有客户。 为了减少内部循环的开销,我根据客户ID对我的数组进行了排序。
这意味着第一个订单对应于我的第一批客户。 E.g:
然后在数组中收集每个相应的订单,直到我到达订单,其客户ID与我的客户ID不对应。然后我退出(中断)我的循环,从包含所有订单的数组中删除我收集的订单(_bestellungenMutArr)并继续下一个客户。
从数组中删除对象非常快,因为对象在大数组的开头是 ALL 。 (另请参阅图表,说明在ridiculousfish中不同阵列操作here的性能。
检查仪器的时间分析器数据,我发现超过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方法。如果客户没有订单,我删除一个空数组(即尝试删除nil?)。 我的猜测是,如果传递一个空数组,方法退出是指令去除,所以这比每次循环检查我的小数组中的内容更有效。或者我错了吗?答案 0 :(得分:1)
您的第二个示例更好,但您仍然会为每个客户列出超过您需要的订单,因为enumerateObjectsUsingBlock:...
每次都从头开始。 (与您的第一个代码示例不同,其中每个客户的订单数量都会缩小。)请尝试使用enumerateObjectsAtIndexes:...
代替,传递使用以bestIndex
开头的NSRange创建的索引集。
或者,您可以使用正常的for循环:for (NSUInteger i = bestIndex; i < [_bestellungenMutArr count]; i++)
,这可能会更快。
答案 1 :(得分:0)
另一个优化级别:
int count = [_bestellungenMutArr count];
for (NSUInteger i = bestIndex; i < count; i++)
为什么?
现在每次都不会遍历[bestellungen MutAte计数]。