Update: see below a better solution than the first.
Here is a solution using NSDictionary wrappers for each number and its index, sorted using a comparator block. It probably doesn't scale very well, but it does its job.
static NSString *const kValueKey = @"value"; static NSString *const kIndexKey = @"index"; + (void)searchArray:(NSArray *)array forClosestValuesTo:(int)value resultValues:(NSArray **)values resultIndexes:(NSArray **)indexes { NSMutableArray *searchObjs = [NSMutableArray arrayWithCapacity:[array count]]; [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { [searchObjs addObject:[NSDictionary dictionaryWithObjectsAndKeys:obj, kValueKey, [NSNumber numberWithUnsignedInt:idx], kIndexKey, nil]]; }]; [searchObjs sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { NSUInteger d1 = ABS([[obj1 objectForKey:kValueKey] intValue] - value); NSUInteger d2 = ABS([[obj2 objectForKey:kValueKey] intValue] - value); if (d1 == d2) { return NSOrderedSame; } if (d1 < d2) { return NSOrderedAscending; } return NSOrderedDescending; }]; NSArray *results = [searchObjs subarrayWithRange:NSMakeRange(0, 3)]; if (values) { *values = [results valueForKey:kValueKey]; } if (indexes) { *indexes = [results valueForKey:kIndexKey]; } }
Update: here's an updated solution that sorts an array of C indices, eliminating the need for an NSDictionary wrapper
static NSString *const kValueKey = @"value"; static NSString *const kArrayKey = @"array"; int CSCompareIndexes(void *data, const void *value1, const void *value2) { NSDictionary *dict = (NSDictionary *)data; NSArray *array = [dict objectForKey:kArrayKey]; int valueToFind = [[dict objectForKey:kValueKey] intValue]; int index1 = *(int *)value1; int index2 = *(int *)value2; NSNumber *num1 = [array objectAtIndex:index1]; NSNumber *num2 = [array objectAtIndex:index2]; return ABS([num1 intValue] - valueToFind) - ABS([num2 intValue] - valueToFind); } void CSSearchNumberArray(NSArray *array, int valueToFind, NSArray **resultValues, NSArray **resultIndexes) { NSInteger numValues = [array count]; NSUInteger *indexes = malloc(sizeof(NSUInteger) * numValues); assert(indexes); int i; for (i = 0; i < numValues; i++) { indexes[i] = i; } NSDictionary *data = [NSDictionary dictionaryWithObjectsAndKeys:array, kArrayKey, [NSNumber numberWithInt:valueToFind], kValueKey, nil]; qsort_r(indexes, numValues, sizeof(NSUInteger), (void *)data, CSCompareIndexes); NSMutableArray *tmpValues = [NSMutableArray arrayWithCapacity:3], *tmpIndexes = [NSMutableArray arrayWithCapacity:3]; for (i = 0; i < 3; i++) { [tmpValues addObject:[array objectAtIndex:indexes[i]]]; [tmpIndexes addObject:[NSNumber numberWithInt:indexes[i]]]; } if (resultValues) { *resultValues = [NSArray arrayWithArray:tmpValues]; } if (resultIndexes) { *resultIndexes = [NSArray arrayWithArray:tmpIndexes]; } free(indexes); } int main (int argc, char *argv[]) { NSAutoreleasePool *pool = [NSAutoreleasePool new]; NSMutableArray *test = [NSMutableArray array]; int i; for (i = 0; i < 10; i++) { [test addObject:[NSNumber numberWithInt:(arc4random() % 100)]]; } NSLog(@"Searching: %@", test); NSArray *values, *indexes; CSSearchNumberArray(test, 50, &values, &indexes); NSLog(@"Values: %@", values); NSLog(@"Indexes: %@", indexes); [pool drain]; return 0; }