Reputation: 10329
I have an NSArray
with Store
objects. Each Store
object has two NSString
objects; StoreID
and Name
.
I would like to check quickly if an ID exists in this NSArray
with Store
objects.
Example:
Store *s1 = [[Store alloc] init];
s1.name = @"Some Name";
s1.id = @"123ABC";
Store *s2 = [[Store alloc] init];
s2.name = @"Some Other Name";
s2.id = @"ABC123";
NSArray *array = [[NSArray alloc] initWithObjects:s1, s2, nil];
NSString *myIdOne = @"ABCDEF";
NSString *myIdTwo = @"123ABC";
BOOL myIdOneExists = ...?
BOOL myIdTwoExists = ...?
Its the ...?
I need to figure out. I know I can do this using a for
loop and break when found... but this seems to me like an nasty approach since the NSArray
could contain thousands of objects,... theoretically.
So I would like to know about a better solution.
Upvotes: 0
Views: 1579
Reputation: 14169
Try this:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@",@"id", myID];
NSArray *filteredArray = [array filteredArrayUsingPredicate:predicate];
if (filteredArray.count > 0)
Store *store = [filteredArray objectAtIndex:0];
Upvotes: 2
Reputation: 237040
Here's the thing: No matter what solution you go with, it will more or less boil down to "loop over the array and return whether or not the object was found." There is no way to search an array more quickly than this unless very specific conditions are met (e.g. the array is already sorted by the value you're searching). You can use a predicate, you can use an enumerator, you can use fast enumeration or you can use a test block — under the hood, they all amount to "loop over the array and perform a test." That's just how arrays work.
If this is something you need to do often and performance is a problem with the naive solution, a sensible solution might be to cache your IDs in an NSSet. Sets are tuned for fast member detection, so you should be able to get your answer much more quickly than you could with an array.
My personal "loop-over-the-array" solution:
BOOL idExists = NSNotFound != [stores indexOfObjectPassingTest:^(Store *store, NSUInteger idx, BOOL *stop) {
return [store.id isEqualToString:@"whatever"];
}];
(Written in the browser, so, y'know, caveat compilor.)
Upvotes: 4
Reputation: 47729
-(BOOL) id:(NSString*) theId existsInArray:(NSArray*) theArray {
for (Store* theStore in theArray) {
if ([theStore.id isEqualToString theId]) {
return YES;
}
}
return NO;
}
Another approach is to implement the isEqual
method in Store
to compare IDs only. Then construct a dummy Store
object with the ID you're looking for and use indexOfObject
or containsObject
, referencing your dummy Store
object.
Upvotes: 1
Reputation: 3208
Simplest solution, just use KVC:
NSArray *results = [array valueForKey:@"id"];
BOOL myIdOneExists = [results containsObject:myIdOne];
BOOL myIdTwoExists = [results containsObject:myIdTwo];
Upvotes: 1