在Objective-C中从数组中删除项目

Cho*_*oli 21 objective-c nsstring nsmutablearray nsarray ios

这个问题看似简单,但我正在寻找最有效和最友好的方式.

假设我有一个Person对象数组.每个人都有一个由头发颜色代表的头发颜色NSString.然后我们说我想从数组中删除头发颜色为棕色的所有Person对象.

我该怎么做呢?

请记住,您无法从枚举的数组中删除对象.

Car*_*zey 28

有两种一般方法.我们可以测试每个元素,然后在符合测试标准的情况下立即删除元素,或者我们可以测试每个元素并存储符合测试条件的元素的索引,然后立即删除所有这些元素.由于存储器使用是一个真正的问题,后一种方法的存储要求可能使其不合需要.

通过"存储所有要删除的索引,然后删除它们"的方法,我们需要考虑前一种方法中涉及的细节,以及它们将如何影响方法的正确性和速度.在这种方法中有两个致命的错误等待.第一种方法是删除不是基于数组中索引的计算对象,而是使用removeObject:方法.removeObject:对数组进行线性搜索以找到要删除的对象.对于大的未分类的数据集,随着时间随着输入大小的平方而增加,这将破坏我们的性能.顺便说一句,使用indexOfObject:然后removeObjectAtIndex:就是那么糟糕,所以我们也应该避免它.第二个致命错误是在索引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];
    }
}
Run Code Online (Sandbox Code Playgroud)

我的测试似乎表明for循环速度略快 - 对于500,000个元素来说可能快了大约四分之一秒,这基本上是8.5到8.25秒之间的差异.所以我建议使用块方法,因为它更安全,感觉更惯用.


Rob*_*Rob 14

假设您正在处理一个可变数组并且它没有被排序/索引(即您必须扫描数组),您可以使用enumerateObjectsWithOptions以下NSEnumerationReverse选项以相反的顺序迭代数组:

[array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    // now you can remove the object without affecting the enumeration
}];
Run Code Online (Sandbox Code Playgroud)

通过以相反的顺序,您可以从枚举的数组中删除一个对象.

  • +1这应该是众所周知的! (3认同)

Ada*_*amG 6

NSMutableArray * tempArray = [self.peopleArray mutableCopy];

for (Person * person in peopleArray){

 if ([person.hair isEqualToString: @"Brown Hair"])
     [tempArray removeObject: person]

}

self.peopleArray = tempArray;
Run Code Online (Sandbox Code Playgroud)

或NSPredicate也有效:http://nshipster.com/nspredicate/


Xco*_*der 5

关键是使用谓词过滤数组。看下面的代码;

- (NSArray*)filterArray:(NSArray*)list
{
    return  [list filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings){
        People *currentObj = (People*)evaluatedObject;
        return (![currentObj.hairColour isEqualToString:@"brown"]);
    }]];
}
Run Code Online (Sandbox Code Playgroud)