2011-08-25 12 views
6

के लिए एनएसएआरएआर खोजना क्या उपयोगकर्ता के इनपुट नंबर से निकटतम (या सटीक अगर यह मौजूद है) मिलान करने के लिए NSArray संख्याओं को खोजने का कोई आसान तरीका है?निकटतम संख्या (ओं)

कहें कि मेरे पास इस तरह की एक सरणी है: 7, 23, 4, 11, 18, 2, और उपयोगकर्ता 5 में प्रवेश करता है।

कार्यक्रम निकटता के अवरोही क्रम में तीन निकटतम मान देता है: 4, 7, 2, और सबसे महत्वपूर्ण बात यह तीन वस्तुओं की NSArray सूचकांक देता है: 2, 0, 5

+0

मुझे लगता है कि मी का सबसे आसान तरीका देखना होगा इनिमुन नंबर, इसे हटाएं, और मिनीमुन नंबर फिर से देखें, आदि – TommyG

+0

मैंने एक लूप लिखकर शुरू किया जो प्रत्येक नंबर का परीक्षण करता है, लेकिन मुझे जल्दी से एहसास हुआ कि मैं मूल से ऑब्जेक्ट्स का सूचकांक प्राप्त नहीं कर पाऊंगा सरणी। यह पता लगाना कि मेरे वास्तविक कार्यक्रम के लिए सूचकांक बहुत महत्वपूर्ण है - जो मैंने यहां पोस्ट किया है वह एक साधारण उदाहरण है, इसलिए मैं सिद्धांत – REDMX

+0

सीख सकता हूं, जो आपको मिलने वाली संख्या की मूल अनुक्रमणिका को ट्रैक करने के लिए बहुत आसान होना चाहिए, लेकिन आप इसे बिना कर सकते हैं सरणी को संशोधित करना मान लें कि आप मिनट पाते हैं, आप इसकी अनुक्रमणिका (तीनों में से अपना पहला नंबर) रखते हैं, फिर इसे हटाने के बजाय, आप इसे अधिकतम संख्या से बदल सकते हैं - इस तरह, आप अपना सरणी नहीं बदलते .... – TommyG

उत्तर

5

अद्यतन: मेरी पहली एक से एक बेहतर समाधान के लिए नीचे देखें।

तुलनात्मक ब्लॉक का उपयोग करके सॉर्टिंग के साथ प्रत्येक नंबर और इसकी अनुक्रमणिका के लिए NSDictionary wrappers का उपयोग करके एक समाधान यहां दिया गया है। यह शायद बहुत अच्छी तरह से स्केल नहीं करता है, लेकिन यह काम पूरा हो जाता है।

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]; 
    } 
} 

अद्यतन: यहाँ एक अद्यतन समाधान है कि इंडेक्सों का एक सी सरणी सॉर्ट करता है, 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; 
} 
+0

यह वास्तव में पूरी तरह से काम करता है - बहुत बहुत धन्यवाद! मैंने कभी इसे अपने आप से नहीं देखा होगा – REDMX

+1

आईएमओ, शब्दकोशों की कोई आवश्यकता नहीं है।आईएसटीएम वे महंगी ओवरकिल हैं। यदि आपके पास इंडेक्स है, तो आपके पास स्वचालित रूप से यह संख्या है जो इंडेक्स है, इसलिए पहले से ही एक एसोसिएशन है। –

+0

@ रुडी यह सच है। मैं जल्द ही अपना जवाब अपडेट करूंगा। –

0

क्या यह एक होमवर्क प्रश्न है? एपीआईएस का उपयोग करके इसे कोड करने का एक आसान तरीका distances नामक एक सरणी उत्पन्न करना है जिसमें प्रत्येक मूल संख्या से दूरी शामिल है, sorted नामक उस सरणी का एक क्रमबद्ध संस्करण बनाएं, फिर को sorted में से कम से कम तीन संख्याओं के लिए इंडेक्स प्राप्त करने के लिए खोजें जो आप मूल संख्या देख सकते हैं।

+0

होमवर्क नहीं, उसके लिए बहुत पुराना है, बस एक नया सवाल है। - मैंने पिछले शोध से जो कुछ लिखा है, मैंने एकत्र किया है, लेकिन मुझे यह नहीं पता कि मूल सरणी से इंडेक्स कैसे प्राप्त किया जाए। क्या मुझे 'दूरी' में कुंजी/मानों का उपयोग करने की आवश्यकता है जहां कुंजी दूरी है और मूल्य सरणी में मूल अनुक्रमणिका है? या क्या मैं कुछ और स्पष्ट याद कर रहा हूँ? – REDMX

+0

@REDMX: आपके प्रश्न के बॉडी में, यदि वे काम नहीं करते हैं, तो भी आपके शोध या कोड के स्निपेट का सारांश शामिल करना उपयोगी है, ताकि उत्तरदाताओं को जो भी पहले से पता हो और फिर से कर सकें अधिक प्रासंगिक, केंद्रित जानकारी दें। यही कारण है कि मैंने पूछा "आपने अभी तक क्या प्रयास किया है?" –

+0

@REDMX: मेरा संशोधित उत्तर देखें। मैं इंडेक्स की एक सरणी बना देता हूं और क्रमशः खोज मूल्य पर संख्याओं की दूरी से सॉर्ट करता हूं। विधि सरणी के पहले तीन आइटमों के साथ मानों के साथ एक सरणी देता है। सरणी में 3 निकटतम मानों के ** अनुक्रमणिका ** शामिल हैं। श्रद्धांजलि या कुछ ऐसे सरणी की आवश्यकता नहीं है, क्योंकि लौटाई गई इंडेक्स (एनएसएनबर्स के रूप में) सीधे मूल्यों से लिंक होती हैं। –

1

अनुभवहीन विधि 5 के लिए स्रोत सरणी खोज करने के लिए, पाया संख्या में भी वृद्धि और उचित जानकारी स्टोर करता है, तो पाया, तो 4 और 6 के लिए खोज, आदि होगा

एक दूसरी विधि एक रखने के लिए किया जाएगा स्रोत सरणी के अनुसार क्रमबद्ध प्रतिलिपि: 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)

आपको इस मामले में केवल तीन तुलना करने की आवश्यकता है, और आपको यह तय करना होगा कि आप < या <= का उपयोग करना चाहते हैं या नहीं। आपकी दूसरी सरणी सिर्फ एन * पीआरटी आकार है, इसलिए यह एक विशाल अंतरिक्ष वृद्धि नहीं है।

+0

+ 1, आप abs() का उपयोग करना चाह सकते हैं ताकि अंतर सकारात्मक हो या नहीं, आप एक अधिक मूल्य घटाते हैं या नहीं। मुझे लगता है कि यदि आप इसे गतिशील रूप से कर रहे थे, तो आप नहीं जानते कि 7-5 या 5-7 का उपयोग करना है या नहीं। –

+0

पहले मेरे पास एक ही विचार था, लेकिन जब तक आप एक क्रमबद्ध सरणी पर काम कर रहे हैं * और * आपने लक्ष्य प्रविष्टि से अधिक पहली प्रविष्टि को सुनिश्चित करना सुनिश्चित किया है, तो आप हमेशा यह जान सकते हैं कि आपको मिली प्रविष्टि है '5' से अधिक, और इसके बाईं ओर प्रविष्टि' 5' से कम या बराबर है। – matthias

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; 
} 
+0

आप केवल 0-3 की सीमा क्यों लौटते हैं? (एनएसएमकेरेंज (0, 3)) – zakdances

+0

प्रश्न देखें। –

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,)

ResultArray है: ( 4, 7,)

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)]" 

     ) 
संबंधित मुद्दे