1

Without unintentionally killing performance, does this appear at first glance to be acceptable for perhaps 200 guid strings in one list compared for equality with 100 guid strings from another list to find the matching indexes.

I have a method signature defined like so...

-(NSArray*)getItemsWithGuids:(NSArray*)guids

And I wanted to take that passed in array of guids and use it in conjunction with this array...

NSArray *allPossibleItems; // Has objects with a property named guid.

... to obtain the indexes of the items in allPossibleItems which have the matching guids from guids

My first instinct was to try indexesOfObjectsPassingTest but after putting together the block, I wondered whether the iOS framework already offers something for doing this type of compare more efficiently.

-(NSArray*)getItemsWithGuids:(NSArray*)guids
    {
        NSIndexSet *guidIndexes = [allPossibleItems indexesOfObjectsPassingTest:^BOOL(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop)
    {
        SomeObjWithGuidProperty *someObject = obj;

        for (NSString *guid in guids) {
            if ([someObject.guid isEqualToString:guid]) {
                return YES;
            }
        }
        return NO;
    }];


    if (guidIndexes) {
        // Have more fun here.
    }
}
5
  • 1
    Don't set *stop to YES in your if statement. Doing that will mean guidIndexes will only ever contain at most 1 index. Commented Mar 14, 2016 at 23:55
  • 1
    Why is the return type of your getItemsWithGuids:forGuids: method set to be NSArray * but you return an NSIndexSet? Commented Mar 14, 2016 at 23:56
  • 1
    Check this thread, comparing different ways. stackoverflow.com/questions/21157109/… Commented Mar 14, 2016 at 23:58
  • @rmaddy Sorry if that was confusing. I'm going to return an array of the matching objects I find in allPossibleItems array using the guidIndexes found in the search. Commented Mar 15, 2016 at 0:01
  • 3
    "guid" sounds to me like a thing that would make a nice NSDictionary key. Maybe a better design even beyond the scope of this question would be to keep your objects-with-guid properties in an indexed data structure, like NSDictionary Commented Mar 15, 2016 at 0:07

4 Answers 4

2

Since you're working with Objective-C (not Swift) check out YoloKit. In your case, you can do something like:

guids.find(^(NSString *guid){
    return [someObject.guid isEqualToString:guid];
});
Sign up to request clarification or add additional context in comments.

2 Comments

A part of me wants to downvote my own post haha. I think my suggestion only reduces the number of lines. It doesn't make the algorithm more efficient.
A part of me wants to up-vote because I think this OP should choose brevity over efficiency for 100-element sized collections. The reason I'm resisting the up-vote instinct is the reliance on net code which I distrust by default. Ehhh +1 anyway, because skimming yolo reminds me of underscorejs, which is a godsend.
1

My thought would be to use a set -

-(NSArray*)getItemsWithGuids:(NSArray*)guids inAllObjects:(NSArray *)allObjects 
{

   NSSet *matchGuids=[NSSet setWithArray:guids];
   NSMutableArray *matchingObjects=[NSMutableArray new];
   for (SOmeObjectWithGuidProperty *someObject in allObjects) {
       if ([matchGuids contains:someObject.guid]) {
           [matchingObjects addObject:someObject];
       }
   }

   return [matchingObjects copy];
}

6 Comments

allGuids should be: NSSet *allGuids = [NSSet setWithArray:guids];. And the for loop should be over allObjects.
Why do you say that? I changed the function signature since in the original question, allPossibleItems comes from nowhere and although the input parameter is called guids it actually seems to contain instances of SomeObjWithGuidProperty
In the OP's code, guids is an array of NSString and allObjects is an array of SomeObjWithGuidProperty.
Answer is actually wrong. [allObjects valueForKey:@"guid"] will return NSArray, not NSSet. Moreover, there is no someObject declaration.
Thanks, that was a typo between my brain and the keyboard.
|
1

Your code looks like it would have O(n^2) performance, which is bad. I think the solution of converting guids to an NSSet and then using NSSet's containsObject would likely be much more performant. You could rewrite your indexesOfObjectsPassingTest code to use an NSSet and containsObject pretty easily.

Comments

1

If order doesn't matter much, I would suggest to change data structure here. Instead of using NSArray, consider to use NSDictionary with guid as key and someObject as value. In this case, you should use -[NSDictionary objectsForKeys:notFoundMarker:] method to obtain objects.

It will work much faster, than enumeration trough 2 arrays. If the NSDictionary key have a good hash function, accessing an element, setting an element, and removing an element all take constant time. NSString has good hash.

-(NSArray*)getItemsWithGuids:(NSArray*)guids {
    NSArray *objectsAndNulls = [allPossibleItemsDictionary objectsForKeys:guids notFoundMarker:[NSNull null]];
    if (objectsAndNulls) {
        // Have more fun here.
        // You should check that object in objectsAndNulls is not NSNull before using it
    }
    return objectsAndNulls;
}

UPD Unfortunately, there is no way to pass nil as notFoundMarker. If you can't provide usable notFoundMarker value and don't want to perform additional checks, you can query objects one by one and fill NSMutableArray. In this case you will avoid pass trough array to remove NSNulls:

-(NSArray*)getItemsWithGuids:(NSArray*)guids {
    NSMutableArray *objects = [NSMutableArray arrayWithCapacity:guids.count];
    for (NSString *guid in guids) {
        SomeObjWithGuidProperty *object = allPossibleItemsDictionary[guid];
        if (nil != object) {
            [objects addObject:object];
        }
    }
    if (nil != objects) {
        // Have more fun here.
    }
    return object;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.