我正在寻找最有效和内存友好的方式。
假设我有一组 Person
对象。每个人都有一种头发颜色,由 NSString
表示。假设我想从头发颜色为棕色的数组中删除所有 Person
对象。
我该怎么做?
请记住,您不能从正在枚举的数组中删除对象。
最佳答案
有两种通用方法。我们可以对每个元素进行测试,如果满足测试条件则立即删除该元素,或者我们可以对每个元素进行测试并存储满足测试条件的元素的索引,然后一次性删除所有这些元素。由于内存使用成为一个真正的问题,后一种方法的存储要求可能使其变得不受欢迎。
通过“存储所有要删除的索引,然后删除它们”的方法,我们需要考虑前一种方法中涉及的细节,以及它们将如何影响方法的正确性和速度。这种方法中有两个 fatal error 等待。第一种是不根据对象在数组中的索引,而是使用 removeObject:
方法来移除已评估的对象。 removeObject:
对数组进行线性搜索以找到要删除的对象。对于大量未排序的数据集,随着时间随输入大小的平方增加,这将破坏我们的性能。顺便说一下,使用 indexOfObject:
然后使用 removeObjectAtIndex:
同样糟糕,所以我们也应该避免它。第二个 fatal error 是从索引 0 开始我们的迭代。NSMutableArray
在添加或删除对象后重新排列索引,因此如果我们从索引 0 开始,我们将保证索引越界异常如果在迭代过程中甚至删除了一个对象。因此,我们必须从数组的尾部开始,只删除索引低于我们目前检查过的每个索引的对象。
说完之后,确实有两个明显的选择:一个从数组末尾而不是开头开始的 for
循环,或者 NSArray
方法 enumerateObjectsWithOptions:usingBlock:
方法。每个示例如下:
[persons enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(Person *p, NSUInteger index, BOOL *stop) {
if ([p.hairColor isEqualToString:@"brown"]) {
[persons removeObjectAtIndex:index];
}
}];
NSInteger count = [persons count];
for (NSInteger index = (count - 1); index >= 0; index--) {
Person *p = persons[index];
if ([p.hairColor isEqualToString:@"brown"]) {
[persons removeObjectAtIndex:index];
}
}
我的测试似乎显示 for
循环稍快一些 - 对于 500,000 个元素可能快四分之一秒,基本上是 8.5 到 8.25 秒之间的差异。所以我建议使用 block 方法,因为它更安全并且感觉更惯用。
关于ios - 按属性值从数组中删除项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19107905/