Paul Peelen
Paul Peelen

Reputation: 10329

Check if NSString exists in custom object in NSArray

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

Answers (4)

tilo
tilo

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

Chuck
Chuck

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

Hot Licks
Hot Licks

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

gschandler
gschandler

Reputation: 3208

Simplest solution, just use KVC:

NSArray *results = [array valueForKey:@"id"];
BOOL myIdOneExists = [results containsObject:myIdOne];
BOOL myIdTwoExists = [results containsObject:myIdTwo];

Upvotes: 1

Related Questions