是否有一种简单的方法可以搜索NSArray
个数字,以找到与用户输入数字匹配的最近(或确切存在)?
假设我有一个这样的数组:7, 23, 4, 11, 18, 2
,用户输入5
。
程序按接近度的降序返回三个最接近的值:4, 7, 2
,最重要的给出三个对象的NSArray
索引:2, 0, 5
答案 0 :(得分:5)
更新:请参阅下面的解决方案,以获得比我的第一个更好的解决方案。
这是一个解决方案,使用NSDictionary包装器为每个数字及其索引,并使用比较器块进行排序。它可能不会很好地扩展,但它可以完成工作。
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];
}
}
更新:这是一个更新的解决方案,可以对C数组索引进行排序,从而无需使用NSDictionary包装器
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;
}
答案 1 :(得分:2)
使用索引数组“间接”对现有值数组进行排序,并按搜索值的“距离”进行排序。排序后的前三项是“最近”的值。
示例:
#import <Foundation/Foundation.h>
@interface NearestSearcher : NSObject { }
+ (NSArray *) searchNearestValuesOf: (int) value inArray: (NSArray *) values;
@end
@implementation NearestSearcher
+ (NSArray *) searchNearestValuesOf: (int) value inArray: (NSArray *) values
{
// set up values for indexes array
NSMutableArray *indexes = [NSMutableArray arrayWithCapacity: values.count];
for (int i = 0; i < values.count; i++)
[indexes addObject: [NSNumber numberWithInt: i]];
// sort indexes
[indexes sortUsingComparator: ^NSComparisonResult(id obj1, id obj2)
{
int num1 = abs([[values objectAtIndex: [obj1 intValue]] intValue] - value);
int num2 = abs([[values objectAtIndex: [obj2 intValue]] intValue] - value);
return (num1 < num2) ? NSOrderedAscending :
(num1 > num2) ? NSOrderedDescending :
NSOrderedSame;
}];
return [indexes subarrayWithRange: NSMakeRange(0, 3)];
}
@end
// DEMO
#define NUM_VALUES 20
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
// DEMO SETUP
// set up values array with random values
NSMutableArray *values = [NSMutableArray arrayWithCapacity: NUM_VALUES];
for (int i = 0; i < NUM_VALUES; i++)
[values addObject: [NSNumber numberWithInt: arc4random() % 200]];
// display values array
for (int i = 0; i < values.count; i++)
NSLog(@"%2d: %4d", i, [[values objectAtIndex: i] intValue]);
// get a random value for x
int x = arc4random() % 200;
// METHOD INVOCATION
NSArray *results = [NearestSearcher searchNearestValuesOf: x inArray: values];
// SHOW RESULTS
NSLog(@"------------------------");
NSLog(@"x: %d", x);
for (NSNumber *num in results)
NSLog(@"%@: %@", num, [values objectAtIndex: [num intValue]]);
[pool drain];
return 0;
}
答案 2 :(得分:1)
天真的方法是在源数组中搜索5
,增加找到的计数并存储相应的信息(如果找到),然后搜索4
和6
等。< / p>
第二种方法是保留源数组的排序副本:
2, 4, 7, 11, 18, 23
然后使用-indexOfObjectPassingTest:
查找该数组中大于5
的第一个数字,然后将该数字与其左邻居进行比较,以查看哪个数字更接近5
:
(7-5) < (5-4) ? storeinfo(7) : storeinfo(4)
如果左邻居获胜,则存储其信息,然后将其左邻居与原来的大于五的数字进行比较:
(7-5) < (5-2) ? storeinfo(7) : storeinfo(2)
但如果右侧获胜,则将其右邻居与失败者进行比较:
(11-5) < (5-2) ? storeinfo(11) : storeinfo(2)
在这种情况下,您只需要进行三次比较,然后您需要决定是否要使用<
或<=
。你的第二个数组只是n * ptr大小,所以它不是一个巨大的空间增长。
答案 3 :(得分:0)
这是一个功课问题吗?使用apis对此进行编码的一种简单方法是生成一个名为distances
的数组,其中包含与每个原始数字的距离,创建一个名为sorted
的数组的排序版本,然后搜索distances
对于sorted
中最低的三个数字,可以获取索引,从中可以查找原始数字。
答案 4 :(得分:0)
经过测试的代码:100%正常工作
NSMutableArray *arrayWithNumbers=[[NSMutableArray alloc]initWithObjects:[NSNumber numberWithInt:7],[NSNumber numberWithInt:23],[NSNumber numberWithInt:4],[NSNumber numberWithInt:11],[NSNumber numberWithInt:18],[NSNumber numberWithInt:2],nil];
NSLog(@"arrayWithNumbers : %@ \n\n",arrayWithNumbers);
NSMutableArray *ResultArray = [ [ NSMutableArray alloc] init];
NSMutableArray *lowestArray = [ [ NSMutableArray alloc] init];
NSMutableArray *tempArray = [ [ NSMutableArray alloc] init];
NSMutableArray *indexArray = [ [ NSMutableArray alloc] init];
NSNumber *numberToFind=[NSNumber numberWithInt:5];
int limitToFilter = 3;
for (NSNumber *number in arrayWithNumbers) {
int a=[number intValue]-[numberToFind intValue];
[lowestArray addObject:[NSNumber numberWithInt:abs(a)]];
}
tempArray=[lowestArray mutableCopy];
NSSortDescriptor *LowestTohighest = [NSSortDescriptor sortDescriptorWithKey:@"self" ascending:YES];
[lowestArray sortUsingDescriptors:[NSArray arrayWithObject:LowestTohighest]];
int upto = limitToFilter-[ResultArray count];
for (int i = 0; i < upto; i++) {
[lowestArray objectAtIndex:i];
if ([tempArray containsObject:[lowestArray objectAtIndex:i]]) {
NSUInteger index=[tempArray indexOfObject:[lowestArray objectAtIndex:i]];
[ResultArray addObject:[arrayWithNumbers objectAtIndex:index]];
[indexArray addObject:[NSIndexSet indexSetWithIndex:index]];
}
}
NSLog(@"ResultArray is : %@ \n\n",ResultArray);
NSLog(@"indexArray is : %@ \n\n",indexArray);
//here release all 4 arrays if u dont need them
<强>输出:强>
arrayWithNumbers :( 7, 23, 4, 11, 18, 2 )
ResultArray是:( 4, 7, 2 )
indexArray是:(
"<NSIndexSet: 0x4e06620>[number of indexes: 1 (in 1 ranges), indexes: (2)]",
"<NSIndexSet: 0x4e04030>[number of indexes: 1 (in 1 ranges), indexes: (0)]",
"<NSIndexSet: 0x4e06280>[number of indexes: 1 (in 1 ranges), indexes: (5)]"
)