NSArray找到对象或对象 - 最佳实践

时间:2013-11-16 22:51:30

标签: ios objective-c nsarray

解决方案: 我已将@ BlackRider的答案标记为正确,因为它是最通用的,特别是对于复杂的比较,但还有其他非常好的答案和评论。我会鼓励任何有相同或类似问题的人审查这些问题并根据您的具体情况评估最佳行动方案。

在我的情况下,我实际上并没有在我的实现中使用BlackRider的解决方案。在@ JoshCaswell的评论和@ voromax对indexesOfObjectsWithOptions:passingTest:的建议的帮助下,我选择使用我自己的解决方案(参见下面的编辑#2),因为在这种情况下我的比较非常简单。

感谢所有回答并提供见解的人。


我正在寻找一种基于该对象的属性(在这种情况下是唯一标识符)从NSArray检索对象的有效方法。在使用Linq的C#.NET中,我会做类似

的事情
MyObject obj = myList.Single(o => o.uuid == myUUID);

我也想知道是否有一种有效的方法来获取与非唯一属性匹配的对象数组。再次,使用Linq它看起来像

List<MyObject> objs = myList.Where(o => o.flag == true).ToList();

当然我可以编写循环来执行此操作,但它们不可重用,我对它们的性能持怀疑态度。

查找具有唯一ID的对象:

-(MyObject*)findObjectWithUUID:(NSString*)searchUUID{
    for (MyObject* obj in _myArray){
        if([obj.uuid isEqualToString: searchUUID])
            return obj;
    }
}

查找对象数组:

-(NSArray*)findObjectsWithFlag:(BOOL)f{
    NSMutableArray* arr = [NSMutableArray array];
    for (MyObject* obj in _myArray){
        if(obj.flag == f)
            [arr addObject:obj];
    }
    return arr;
}

- 编辑 -

幸运的是,在第一种情况下,我要找的对象有一个唯一的标识符,我知道只有一个。我想出了一个在我的对象上实现isEqual的解决方案,它将由indexOfObject:

调用
- (BOOL)isEqual:(id)object{
    return [self.uuid isEqualToString: ((MyObject*)object).uuid];
}

然后创建一个“假”查找对象并使用它来查找真实的

MyObject *lookupObject = [[MyObject alloc] init];
lookupObject.uuid = searchUUID;
MyObject *actualObject = 
    [_myArray objectAtIndex:[_myArray indexOfObject:lookupObject]];

这与我上面发布的for-in循环基本相同,但可能更具可读性和优势。更可重复使用。当然,这只适用于找到一个独特的对象,而不是解决我问题的后半部分。

- 编辑2 -

根据评论中的建议检查Class并实施hash

- (BOOL)isEqual:(id)object{
    return [object isKindOfClass:[MyObject class]] && 
           [self.uuid isEqualToString: ((MyObject*)object).uuid];
}

- (NSUInteger)hash{
    return [self.uuid hash];
}

5 个答案:

答案 0 :(得分:37)

您可以使用[NSPredicate],它为您提供类似查询的搜索语法。查看this page以获取谓词语法描述。这是一个简单的例子:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"propertyName == %@", @"value"];
NSArray *filteredArray = [myArray filteredArrayUsingPredicate:predicate];

至于性能,我认为您的解决方案没问题,因为数组中的任何搜索都需要遍历所有元素,然后,对于每个对象,将字段的值与您搜索的值进行比较。您可以优化相同数据中的重复搜索,例如通过创建和填充将某些字段的值映射到匹配对象(或对象集合,如果映射是一对多)的字典。

答案 1 :(得分:14)

您还可以查看支持并发和搜索顺序的现代块语法:indexOfObjectWithOptions:passingTest:indexesOfObjectsWithOptions:passingTest:

答案 2 :(得分:10)

我被rmaddys评论所吸引,所以我检查了循环和谓词之间的区别。

让我们假设一个带有NSString属性的简单对象。我已经将它插入数组10 000次,每次都有不同的属性值。

在最坏的情况下,当所需对象位于数组的最后位置时,循环方法比NSPredicate快3.5倍(0.39s vs 0.11s,arraySize = 10000,10次迭代,iPad Mini)

我用于参考的代码:pastebin

答案 3 :(得分:3)

对于那些感兴趣的人,我发现通过NSArray搜索的最快方法是在后台线程上使用for循环。使用[self performSelectorInBackground ...]方法。 在一个10000个自定义对象的NSArray中,我在大约1秒内彻底搜索了整个事物。在主线程上花费大约10秒或更长时间。

答案 4 :(得分:3)

我知道它与NSArray有关,但如果我们使用Swift并使用swift数组struct,那么这将更加容易。

Swift 2.2 / Swift 3.0 / Swift 4.x 适用于所有版本

让我们假设我们有一个自定义模型类

class User {
    var userId = 0
    var userName = ""
} 

我们假设我们有一个名为usersArray的数组,其中包含User类的自定义对象。

我们想要使用userId = 100从这个数组中获取一个对象,例如: -

let filteredArray = usersArray.filter({$0.userId == 100}) 

此过滤后的数组将包含userId为100

的所有自定义对象
print(filteredArray[0].userName) //will print the name of the user with userId = 100