I am trying to implement a binary search using objective-c blocks. I am using the function indexOfObject:inSortedRange:options:usingComparator:
. Here is an example.
// A pile of data.
NSUInteger amount = 900000;
// A number to search for.
NSNumber* number = [NSNumber numberWithInt:724242];
// Create some array.
NSMutableArray* array = [NSMutableArray arrayWithCapacity:amount];
for (NSUInteger i = 0; i < amount; ++i) {;
[array addObject:[NSNumber numberWithUnsignedInteger:i]];
}
NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];
// Run binary search.
int index1 = [array indexOfObject:number
inSortedRange:NSMakeRange(0, [array count])
options:NSBinarySearchingFirstEqual
usingComparator:^(id lhs, id rhs) {
if ([lhs intValue] < [rhs intValue]) {
return (NSComparisonResult)NSOrderedAscending;
} else if([lhs intValue] > [rhs intValue]) {
return (NSComparisonResult)NSOrderedDescending;
}
return (NSComparisonResult)NSOrderedSame;
}];
NSTimeInterval stop1 = [NSDate timeIntervalSinceReferenceDate];
NSLog(@"Binary: Found index position: %d in %f seconds.", index1, stop1 - start);
// Run normal search.
int index2 = [array indexOfObject:number];
NSTimeInterval stop2 = [NSDate timeIntervalSinceReferenceDate];
NSLog(@"Normal: Found index position: %d in %f seconds.", index2, stop2 - start);
I wonder how I can use an externally defined objective-c block with the aforementioned function. Here are two compare functions.
NSComparisonResult compareNSNumber(id lhs, id rhs) {
return [lhs intValue] < [rhs intValue] ? NSOrderedAscending : [lhs intValue] > [rhs intValue] ? NSOrderedDescending : NSOrderedSame;
}
NSComparisonResult compareInt(int lhs, int rhs) {
return lhs < rhs ? NSOrderedAscending : lhs > rhs ? NSOrderedDescending : NSOrderedSame;
}
Those are written in reference to the following declarations which can be found in NSObjCRuntime.h
.
enum _NSComparisonResult {NSOrderedAscending = -1, NSOrderedSame, NSOrderedDescending};
typedef NSInteger NSComparisonResult;
typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);
You can define a block as a global variable to get an effect similar to functions.
NSComparisonResult (^globalBlock)(id,id) = ^(id lhs, id rhs) {
if([lhs intValue] < [rhs intValue]) {
return (NSComparisonResult)NSOrderedAscending;
} else if([lhs intValue] > [rhs intValue]) {
return (NSComparisonResult)NSOrderedDescending;
}
return (NSComparisonResult)NSOrderedSame;
};
Then, in the method doing the comparison:
int index1 = [array indexOfObject:number
inSortedRange:NSMakeRange(0, [array count])
options:NSBinarySearchingFirstEqual
usingComparator:globalBlock];
To put the block in a header, for external use:
NSComparisonResult (^globalBlock)(id,id);
I know this is old, but I just ran across it and I've been trying to work on my blocks foo, so here goes...
I created a method that returns your NSComparator as a block. It looks like this:
-(NSComparisonResult (^) (id lhs, id rhs))compareNSNumber{
return [[^(id lhs, id rhs)
{
return [lhs intValue] < [rhs intValue] ? (NSComparisonResult)NSOrderedAscending : [lhs intValue] > [rhs intValue] ? (NSComparisonResult)NSOrderedDescending : (NSComparisonResult)NSOrderedSame;
} copy ] autorelease];
}
I was then able to run your sample code by changing the binary search execution to:
// Run binary search.
int index1 = [array indexOfObject:number
inSortedRange:NSMakeRange(0, [array count])
options:NSBinarySearchingFirstEqual
usingComparator:[self compareNSNumber]];
NSTimeInterval stop1 = [NSDate timeIntervalSinceReferenceDate];
NSLog(@"Binary: Found index position: %d in %f seconds.", index1, stop1 - start);
I got very similar output to the original implementation with the block definition within the method call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With