从NSMutableArray中提取特定数据的速度更快?

时间:2013-11-30 02:20:38

标签: ios objective-c arrays sorting

我有一个充满了我创建的名为“问题”的NSObjects数组。 每个问题的一个属性是它属于哪个级别。 如果用户选择了玩2级,我想获得所有具有.level属性为2的问题。现在我正在循环查看所有问题以找到匹配项,但这需要~2秒才能在iPad上运行3 /新iPad设备。有没有更快的方法来处理这样的情况?

int goThrough = 0;    
do {
      Question *currentQuestion = [allQs objectAtIndex:(goThrough)];

      if (currentQuestion.level == levelChosen) {
             [questions addObject:currentQuestion];
      }
      goThrough++;
    } while (goThrough < [allQs count]);

非常感谢您的帮助!

5 个答案:

答案 0 :(得分:5)

如果您必须定期按级别组织问题,那么为什么不按级别组织所有问题。创建数组字典。每个键,如果级别和每个数组是该级别的问题列表。你这样做一次,将问题提升到一个水平变得微不足道。

答案 1 :(得分:0)

我建议使用NSArray方法enumerateObjectsUsingBlock或其中一个变体。甚至有变体将同时循环遍历数组元素。你可能需要使用一个锁来向你的问题数组中添加元素,因为我怀疑NSMutableArray的addObject方法是否是线程安全的。

您应该针对具有锁定的并发版本测试非并发版本,以查看哪个版本更快。哪种方法更快将取决于allQs数组中有多少对象属于当前级别。如果只有少数属于,则断言锁定的代码不会经常触发,并发性的好处将超过断言锁定的时间代价。如果allQs数组中的大多数对象与所选级别匹配,代码将最终花费大量时间断言锁,并且并发线程仍将等待其他线程释放锁。

修改后的代码可能如下所示:

单线程版本:

[allQs enumerateObjectsUsingBlock:
   ^(Question *currentQuestion, NSUInteger index, BOOL *stop)
   {
     if (currentQuestion.level == levelChosen)
       [questions addObject:currentQuestion];
   }
];

并发版本:

[allQs enumerateObjectsWithOptions:
     NSEnumerationConcurrent
   usingBlock:
   ^(Question *currentQuestion, NSUInteger index, BOOL *stop)
   {
     if (currentQuestion.level == levelChosen)
       @synchronized
       {
         [questions addObject:currentQuestion];
       }
   }
];

实际上,现在我考虑一下,通过首先使用indicesOfObjectsWithOptions:passingTest对数组进行并发传递,您可能会获得更快的性能。在该传递中,您将构建与当前级别匹配的所有对象的NSIndexSet。然后在一次传递中,您将这些元素提取到另一个数组中:

NSIndexSet *questionIndexes = [allQs indexesOfObjectsWithOptions: NSEnumerationConcurrent        
  usingBlock:
  ^(Question *currentQuestion, NSUInteger index, BOOL *stop)
  {
    return (currentQuestion.level == levelChosen)
  }
];
questions = [allQs objectsAtIndexes: questionIndexes];

另一张海报指出,你最好提前提升你的问题阵列。如果这对你的程序流程有效,那就更好了,因为根本不过滤你的数组总是比最高度优化的过滤代码更快。

答案 2 :(得分:0)

你总是可以使用快速枚举(除非你打算改变对象是枚举集合的最快方法)。像这样:

for (Question *thisQuestion in allQs) {
    if (thisQuestion.level == levelChosen) 
        [questions addObject:thisQuestion];
    }
}

由于您没有改变正在迭代的集合(allQs),这样可以正常工作并且比使用enumerateObjectsUsingBlock更快。如果您需要迭代的数组索引(allQs),请使用enumerateObjectsUsingBlock

答案 3 :(得分:0)

我暂时无法访问Mac,但你可以尝试一下:

[allQs  enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger index, BOOL *stop) {
  Question *currentQuestion = [allQs objectAtIndex:index];
  if (currentQuestion.level == levelChosen) {
    [questions addObject:currentQuestion];
  }
}

这将使用您设备的所有核心,因此它可以快两倍

答案 4 :(得分:0)

似乎缺少一个简单的答案。如果要过滤数组的对象只剩下某些对象,-filteredArrayUsingPredicate:就是你想要的。它可以非常简单地完成。

NSPredicate *p = [NSPredicate predicateWithBlock:^(Question *aQuestion, NSDictionary *bindings){
    return (aQuestion.level==2);
}];
NSArray *filteredArray = [originalArray filteredArrayUsingPredicate:p];