Challenge 2 - Uses Function


#1


#import <Foundation/Foundation.h>

//This function takes an array and a string to look up in it.  It will iterate through the array and return true (and exit quickly) if found.
BOOL stringInArray( NSArray *stringArray, NSString *s ){
   
    for (NSString *arrayString in stringArray){
        if ([arrayString caseInsensitiveCompare:s] != NSOrderedSame) {
            return TRUE;
        }
    }
    
    //Will never get here if it returns true
    return FALSE;
}


int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        //Load up propernames
        NSString *nameString = [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames" encoding:NSUTF8StringEncoding error:NULL];
        
        //load up words list
        NSString *wordString = [NSString stringWithContentsOfFile:@"/usr/share/dict/words" encoding:NSUTF8StringEncoding error:NULL];
        
        //Break into arrays
        NSArray *names = [nameString componentsSeparatedByString:@"\n"];
        NSArray *words = [wordString componentsSeparatedByString:@"\n"];
        
        //Init counter (just for output reasons)
        int matchesCounter = 0;

        //go through one string at a time
        for (NSString *n in names) {
            
            //Call function above to see if it is in the words array
            if ( stringInArray(words, n) ) {
                matchesCounter++;
                NSLog(@"%i %@", matchesCounter, n);
            }

        }
        
    }
    return 0;
}

I felt that creating a function makes the code easy to read and simplistic.


#2

Your solution doesn’t actually work. When I run it, it returns 1,309 matches which is how many names are in the names array. Realistically it should be returning around 293 matches out of the 1,309 names.

I thought your solution was promising because it ran pretty quickly, however when I updated it to do a case-sensitive compare against a lowercase name it took over 10 seconds to run, which is how long it took to run my own program. I’m trying to come up with a more efficient solution, any ideas?

Here is my original solution:

[code]#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
@autoreleasepool {
NSDate *startTime = [[NSDate alloc] init];

    // Get the contents of the names and words files
    NSString *nameString = [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames"
                                                     encoding:NSUTF8StringEncoding
                                                        error:NULL];
    NSString *wordString = [NSString stringWithContentsOfFile:@"/usr/share/dict/words"
                                                     encoding:NSUTF8StringEncoding
                                                        error:NULL];
    
    // Split all of the words and names into an array
    NSArray *names = [nameString componentsSeparatedByString:@"\n"];
    NSArray *words = [wordString componentsSeparatedByString:@"\n"];
    int matchCounter = 0;

    // Iterate over the names and search for them in the words array
    for (NSString *n in names) {

        // If a match is found, output it to the console and increment the counter
        if ([words indexOfObject:[n lowercaseString]] != NSNotFound && [n length] > 0) {
            NSLog(@"%i %@", ++matchCounter, n);
        }
    }
    
    NSDate *endTime = [[NSDate alloc] init];
    NSLog(@"There were %i matches out of the %lu possibilities in %.2f seconds.",
            matchCounter, [names count], [endTime timeIntervalSinceDate:startTime]);
}

return 0;

}[/code]


#3

OOp, I stand corrected…

This way provides the fastest solution possible… It requires the lists to be sorted, which they are, so in theory, theres no reason to search through the prior results. Ive done routines like this is the past in other languages and always sort first.

The function now takes a startAT parameter which is passed back to main by reference, and can pick up where you left off in the words list. See comments in code for details

#import <Foundation/Foundation.h>

//This function takes an array and a string to look up in it.  It will iterate through the array and return true (and exit quickly) if found.  It also incorperates a startAT parameter that allws you to start at a certain point in the array
BOOL stringInArray( NSArray *stringArray, NSString *s, int *startAt ){
    

    for (int i = *startAt; i <= stringArray.count-1; i++ ){
        if ([stringArray[i] compare:s options:NSCaseInsensitiveSearch] == NSOrderedSame) {
            
            *startAt = i;
            if ( i+1 == stringArray.count )
                break;
            
            if ([stringArray[i+1] caseInsensitiveCompare:s] == NSOrderedSame)
            {
            
                if([stringArray[i+1] isEqualToString:s] == FALSE)
                    return TRUE;
                else
                    return FALSE;
            }
                    
            
            return FALSE;
           
        }
    }
    
    //Will never get here if it returns true
    return FALSE;
}


int main(int argc, const char * argv[])
{
    
    @autoreleasepool {
        
        //Load up propernames
        NSString *nameString = [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames" encoding:NSUTF8StringEncoding error:NULL];
        
        //load up words list
        NSString *wordString = [NSString stringWithContentsOfFile:@"/usr/share/dict/words" encoding:NSUTF8StringEncoding error:NULL];
        
        //Break into arrays
        NSArray *names = [nameString componentsSeparatedByString:@"\n"];
        NSArray *words = [wordString componentsSeparatedByString:@"\n"];
        
        //Init counter (just for output reasons)
        int matchesCounter = 0;
        
        //Since list is sorted, Only continue on iterating through words list by picking up where you left off last.
        //stringInArray passes back the last search position by reference through the startAT parameter
        int startRange = 0;
        
        //go through one string at a time
        for (NSString *n in names) {
            
            //Call function above to see if it is in the words array
            if ( stringInArray(words, n, &startRange) ) {
                matchesCounter++;
                NSLog(@"%i %@", matchesCounter, n);
            }
            
        }
        
    }
    return 0;
}