Hi all! I’m just learning Objective C, so I would really appreciate any feedback on this. I’m getting 293 matches, ending with “Woody”.
// Read in all names
NSString *nameString = [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames"
encoding:NSUTF8StringEncoding
error:NULL];
// Read in all words
NSString *wordString = [NSString stringWithContentsOfFile:@"/usr/share/dict/words"
encoding:NSUTF8StringEncoding
error:NULL];
// Break all names and words into arrays of strings
NSArray *names = [nameString componentsSeparatedByString:@"\n"];
NSArray *words = [wordString componentsSeparatedByString:@"\n"];
// Do the actual check
int matches = 0;
for (NSString *aWord in words) { // Go through every word
if ([aWord isEqualToString:[aWord lowercaseString]]) { // Is the word lowercase?
for (NSString *aName in names) { // If it's lowercase then go through every name
if ([aWord isEqualToString:[aName lowercaseString]]) {
// If this lowercase word also appears in propernames then it's a match!
matches ++;
NSLog(@"Match %i: %@", matches, aWord);
}
}
}
293 matches is correct, but the code can be more efficient. For example, don’t check all of the words for each name, just check the 1309 names (converted to lowercase) with each word, until a match is found – then break out of the inner loop. No need to go through the rest of the words once a match is found.
For an even bigger array, you could check just part of the array. For example, for “Al”, check only the words starting with a, then break. To investigate how many checks are actually done with different approaches, it helps to keep count for testing purposes.
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
int numMatches = 0;
int numChecks = 0;
// Read in the propernames file as a large string.
NSString *properNames = [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames"
encoding:NSUTF8StringEncoding
error:NULL];
// Create an array of proper names (all are capitalized).
NSArray *namesAr = [properNames componentsSeparatedByString:@"\n"];
// Read in the words file as a large string.
NSString *words = [NSString stringWithContentsOfFile:@"/usr/share/dict/words"
encoding:NSUTF8StringEncoding
error:NULL];
// Create an array of words.
NSArray *wordsAr = [words componentsSeparatedByString:@"\n"];
// Find proper names that match lower case equivalents in the words array.
for (NSString *pn in namesAr) {
NSString *pn_lc = [pn lowercaseString];
for (NSString *wd in wordsAr) {
numChecks++;
if ([pn_lc isEqualToString:wd] && [wd isNotEqualTo:@""]) {
numMatches++;
NSLog(@"Match %i: %@ / %@", numMatches, pn, wd);
break;
}
}
}
NSLog(@"Total number of proper names: %lu", (unsigned long)[namesAr count]);
NSLog(@"Number of words checked: %lu", (unsigned long)[wordsAr count]);
NSLog(@"\nTotal number of checks: %i", numChecks);
}
return 0;
}
Output:
. . .
2014-01-19 20:44:18.946 Chall_17_2_WordsNames[18638:303] Match 292: Wolf / wolf
2014-01-19 20:44:18.961 Chall_17_2_WordsNames[18638:303] Match 293: Woody / woody
2014-01-19 20:44:18.978 Chall_17_2_WordsNames[18638:303] Total number of proper names: 1309
2014-01-19 20:44:18.978 Chall_17_2_WordsNames[18638:303] Number of words checked: 235887
2014-01-19 20:44:18.979 Chall_17_2_WordsNames[18638:303]
Total number of checks: 273861512
Thank you very much! Much cleaner and more efficient!