Challenge #2 Solution (Seems to be very fast)


#1

I realized that since the second array had all the proper names and words in it, I didn’t need the first proper names file at all. So here is my code for Challenge #2. I’d love some feedback on it, if there is anything anyone finds wrong with it, or ways it could improve. I finally feel like I’m getting this (2nd time through the book).

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

@autoreleasepool {
    
	// Read in the file (of words and names) as one huge string
	NSString *wordsAndNames = [NSString stringWithContentsOfFile:@"/usr/share/dict/words"
																							encoding:NSUTF8StringEncoding
																									error:NULL];
    
	// Break it into an array of strings
	NSArray *words = [wordsAndNames componentsSeparatedByString:@"\n"];
	
	// Make an NSUInteger named "wordCount" that holds the number of items in the array
	NSUInteger wordCount = [words count];
	
	// Initialize an int named "counter" to keep track of how many proper names there are, that are also words.
	int counter = 0;
	
	/* Iterate through the array (Had to do this the long way, because of the code below. Don't know how I could use this code using fast enumeration...) */
	for (int i = 0; i < wordCount; i++) {

		/* This "if" statement keeps the program from throwing an exception, since you're adding 1 to wordCount during the following statements. If you try to compare the last string in the array to the next string (which is nil) the program will crash. */
		if (i + 1 < wordCount) {

			/* This "if" statement compares the string at one index to the string at the next index. If they are the same (disregarding case) then it will print the first string (the proper name) */
			if ([[words objectAtIndex: i] caseInsensitiveCompare: [words objectAtIndex: i + 1]] == NSOrderedSame) {

				// Increase the counter
				counter++;

				// Print the proper name
				NSLog(@"%@", [words objectAtIndex: i]);
			}
		}
	}
	// Print a blank line, followed by the total number of words in the array, followed by the number of proper names.
	NSLog(@"\n");
	NSLog(@"There are %lu total words in the array.", (unsigned long)wordCount);
	NSLog(@"%d of them are proper names.", counter);
}
return 0;

}[/code]

What I like about it, as far as speed goes, is that it’s just going through one array, one time, instead of comparing two arrays simultaneously. My program finishes in under 2 seconds.

Comments?


#2

Excellent (of course, you are assuming that the file is sorted.)

As a further learning exercise, challenge yourself and do this in pure C: that is, using an array of character strings (char*[], which you need to create with malloc), fopen and fscanf to read in the words, strcmp or strcasecmp to compare strings, and of course printf to print.


#3

Hi Striker37!!

My solution for this exercise was made by pretty much, the same approach you did (using just the words file as it’s sorted and contains the proper names too) but then, I realize that not all consecutive words, one in upper case and the other one in lower case are names, 'cause, for example, there’s an “a” and an “A” that doesn’t sounds like a name for me… So, that makes me reorder my ideas and I thought that the proper names file has to be used to check that 2 consecutive words are a proper name too.

My final solution gave me 293 matches and 2,219,021 iterations made … which is a lot for me, and I think, can be optimized…

I’ll be waiting for all kind of comments!!!

Here it is:

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {
        
        //Read in a file from a path as a large string (for each file)
        
        NSString *aWordsFile = [NSString stringWithContentsOfFile:@"/usr/share/dict/words"
                                                         encoding:NSUTF8StringEncoding
                                                            error:NULL];
        
        NSString *aNamesFile = [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames"
                                                         encoding:NSUTF8StringEncoding
                                                            error:NULL];
        
        //Break the file to fill the array one by one, splitting them each time a line break is found
        
        NSArray *words = [aWordsFile componentsSeparatedByString:@"\n"];
        NSArray *names = [aNamesFile componentsSeparatedByString:@"\n"];
        
        //Get the lenght of the words Array
        
        NSInteger arrayLength = [words count];
        
        //Use a counter to get the number of proper names that can be used as a regular word too
        //Use another counter to check the number of iterations made to acomplish this challenge
        
        NSInteger namesCounter = 0;
        int iteration = 0;
        
        //Iterate through the array one by one
        
        for (int i=0;i< arrayLength-1;i++){
            
            //Store the actual word and the next to compare themselves
            
            NSString *actualWord = [words objectAtIndex:i];
            NSString *nextWord = [words objectAtIndex:i+1];
            
            if ([actualWord caseInsensitiveCompare] == NSOrderedSame){
                
                //If the above conditional gives a match, search for that word within the names Array
                
                for(NSString *s in names){
                    if ([actualWord isEqualToString:s]){
                        NSLog(@"This is a proper name (%@) and a regular word too (%@)",actualWord,nextWord);
                        namesCounter++;
                    }
                    iteration++;
                }
            }
            iteration++;
        }
        
        //Print the number of proper names matched and how many iterations were required to end the task
        
        NSLog(@"There are %ld proper names matched and %d iterations made", namesCounter, iteration);
        
        return 0;
    }
}

#4

[b][quote=“MiguelRC86”]
for(NSString *s in names){
if ([actualWord isEqualToString:s]){
NSLog(@“This is a proper name (%@) and a regular word too (%@)”,actualWord,nextWord);
namesCounter++;
}

[/quote][/b]

I have made an improvement updating the above code with this:

                if ([names containsObject:actualWord]){
                    NSLog(@"This is a proper name (%@) and a regular word too (%@)",actualWord,nextWord);
                    namesCounter++;
                }

This code has done the job, passing from 2,219,021 iterations to “just” 235,886 :slight_smile:


#5

Well guys this has been puzzling me for ages this one!
I tried to do it on my own but I think I would have taken forever to figure out how to do it.
What am I doing wrong?
Any advice is much appreciated!


#6

Well Ricky87, I was ready to send my mac straight into the wall 'cause it took me a lot of time to figure out how to solve this Challenge, but then I remember one of Steve mantras: “Focus and Simplicity”

A lot of patience and just that…

I don’t know what the other guys around think, but I think that definitely the best way to solve a problem is really understand what the hell is going on, and for that there’s nothing better than a paper a pencil and pseudocode.

Try it.


#7

Good solution.

My version:

#import <Foundation/Foundation.h>

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

	NSString *allWords = [NSString stringWithContentsOfFile:@"/usr/share/dict/words" encoding:NSUTF8StringEncoding error:NULL];
	NSArray *wwords = [allWords componentsSeparatedByString:@"\n"];
	wwords = [wwords sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
	
	int itirations = 0;
	
	for(int i = 0; i < [wwords count]-1; i++) {
		if ([[wwords objectAtIndex: i] caseInsensitiveCompare: [wwords objectAtIndex: i + 1]] == NSOrderedSame) {
			NSLog(@"Found : %@: %@", [wwords objectAtIndex:i],[wwords objectAtIndex:i+1]);
			i++; }
		itirations++;
		}
	NSLog(@"\nWord count: %lu, itirations: %i\n", [wwords count], itirations);
}
return 0;

}

I sorted the array, even if I knew it was already sorted, but I thought it could broaden the use.

I also figured that, in a sorted list, the value searched necessarily had to be the next one and that the list should be searched 1 item further in case a match was found.


#8

Gives me all names with ‘wolf’ in it, case insensitive.


        // Read file propernames
        NSString *nameString =
        [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames"
                                  encoding:NSUTF8StringEncoding
                                     error:NULL];
        
        // Read file words
        NSString *nameStringTwo =
         
         [NSString stringWithContentsOfFile:@"/usr/share/dict/words"
                                  encoding:NSUTF8StringEncoding
                                     error:NULL];
        
        //Create an empty mutable array
        NSMutableArray *nameArray = [[NSMutableArray alloc] init];
        
        
        // Add two names list to the array
        [nameArray addObject:nameString];
        [nameArray addObject:nameStringTwo];
        
        // Break it into an array of strings
        NSArray *names = [nameString componentsSeparatedByString:@"\n"];
        NSArray *namesTwo = [nameStringTwo componentsSeparatedByString:@"\n"];

        // Go through the array one string at a time
        for (NSString *n in names, namesTwo) {
            
            // Look for the string "wolf" in a case-insensitive manner
            NSRange r = [n rangeOfString:@"Wolf" options:NSCaseInsensitiveSearch];
            
            // Was it found?
            if (r.location != NSNotFound) {
                NSLog(@"%@", n);

#9

[quote=“ibex10”]Excellent (of course, you are assuming that the file is sorted.)

As a further learning exercise, challenge yourself and do this in pure C: that is, using an array of character strings (char*[], which you need to create with malloc), fopen and fscanf to read in the words, strcmp or strcasecmp to compare strings, and of course printf to print.[/quote]

why this line works

if ([[words objectAtIndex: i] caseInsensitiveCompare: [words objectAtIndex: i + 1]] == NSOrderedSame)

I don’t think this line work because the first word in the array might be equal to the 10th word in the array.
In this code, he is basically comparing word at index 0 with word at index 1, word at index 1 with word at index 2, who knows that the word at index 0 might be equal to word at index 20. Therefore this line of code won’t work. Correct me if I’m wrong


#10

[quote=“plaisance”]Gives me all names with ‘wolf’ in it, case insensitive.

[code]

    // Read file propernames
    NSString *nameString =
    [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames"
                              encoding:NSUTF8StringEncoding
                                 error:NULL];
    
    // Read file words
    NSString *nameStringTwo =
     
     [NSString stringWithContentsOfFile:@"/usr/share/dict/words"
                              encoding:NSUTF8StringEncoding
                                 error:NULL];
    
    //Create an empty mutable array
    NSMutableArray *nameArray = [[NSMutableArray alloc] init];
    
    
    // Add two names list to the array
    [nameArray addObject:nameString];
    [nameArray addObject:nameStringTwo];
    
    // Break it into an array of strings
    NSArray *names = [nameString componentsSeparatedByString:@"\n"];
    NSArray *namesTwo = [nameStringTwo componentsSeparatedByString:@"\n"];

    // Go through the array one string at a time
    for (NSString *n in names, namesTwo) {
        
        // Look for the string "wolf" in a case-insensitive manner
        NSRange r = [n rangeOfString:@"Wolf" options:NSCaseInsensitiveSearch];
        
        // Was it found?
        if (r.location != NSNotFound) {
            NSLog(@"%@", n);

[/code][/quote]

I think you didn’t get the point of the exercise…

[quote=“chanyeechoong”][quote=“ibex10”]Excellent (of course, you are assuming that the file is sorted.)

As a further learning exercise, challenge yourself and do this in pure C: that is, using an array of character strings (char*[], which you need to create with malloc), fopen and fscanf to read in the words, strcmp or strcasecmp to compare strings, and of course printf to print.[/quote]

why this line works

if ([[words objectAtIndex: i] caseInsensitiveCompare: [words objectAtIndex: i + 1]] == NSOrderedSame)

I don’t think this line work because the first word in the array might be equal to the 10th word in the array.
In this code, he is basically comparing word at index 0 with word at index 1, word at index 1 with word at index 2, who knows that the word at index 0 might be equal to word at index 20. Therefore this line of code won’t work. Correct me if I’m wrong[/quote]

If you take a look at the file: ‘wolf’ and ‘Wolf’ are one next to the other. So you optimize the program having in mind that the list is ordered alphabetically. This way you can code optimally. Of course you cannot use this code while using a file that it’s not ordered alphabetically.


#11

I think the challenge would like to see both lists compared, so here is my solution. Please correct me if I’m wrong here, I’m very new to this.

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

@autoreleasepool {
    
    //Read in a file as a huge string (ignoring the possiblility of an error)
    NSString *nameString = [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames"
                                                     encoding:NSUTF8StringEncoding
                                                        error:NULL];
    
    NSString *wordString = [NSString stringWithContentsOfFile:@"/usr/share/dict/words"
                                                     encoding:NSUTF8StringEncoding
                                                        error:NULL];
    
    //Break lists into an array of strings
    NSArray *namesArray = [nameString componentsSeparatedByString:@"\n"];
    NSArray *wordsArray = [wordString componentsSeparatedByString:@"\n"];
    
    //Creating an integer to count the number of itterations
    int itteration = 0;
    
    //Itterates through the word list
    for (NSString *word in wordsArray) {
        //Itterates through the name list
        for (NSString *name in namesArray) {
            //Compare the name and word only prints if the word is lowercase
            if (([word caseInsensitiveCompare: name] == NSOrderedSame) && ([word isNotEqualTo: name])) {
                NSLog(@"\nThe name is %@ and the word is %@.\n",name,word);
            }
            itteration ++;
        }
        itteration ++;
    }
    
    NSLog(@"\nThere where %d itterations.\n",itteration);
    
}
return 0;

}


#12

Hi, Im very new ,tell me what could i improve plz, this is my code:

#import <Foundation/Foundation.h>

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

    @autoreleasepool {
        
        //Read in a file as a huge string ( ignoring the possibilty of an error)
        
        NSString *wordsString = [NSString stringWithContentsOfFile:@"/usr/share/dict/words"
                                                         encoding:NSUTF8StringEncoding
        
                                                            error:NULL];
        
        NSString *namesString = [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames"
                                                          encoding:NSUTF8StringEncoding
                                                             error:NULL];
        
        
        
        NSArray *words = [wordsString componentsSeparatedByString:@"\n"];
        NSArray *names = [namesString componentsSeparatedByString:@"\n"];
        
        
        

        NSUInteger numberCount = [words count];
        for (int i = 0; i < numberCount; i ++) {
            
            NSString *wordInMem = words[i];
            
            NSInteger numberCountN = [names count];
            
            for (int i=0; i< numberCountN; i ++) {
                
            
            NSString *nameInMem = names [i];
            
                if ((([wordInMem caseInsensitiveCompare:nameInMem]) == NSOrderedSame) && ([wordInMem isNotEqualTo:nameInMem]){
                    
                    if (([wordInMem caseInsensitiveCompare:nameInMem]) == NSOrderedSame) {
                        
                        NSLog(@"The name is %@ and the word is %@",nameInMem,wordInMem);
                   
                    }
                }
            }
        }
    }
    return 0;
}






#13

This was hard. Inspired by the solutions posted here, this is the solution, which seems to work well:

[code]
@autoreleasepool {

    //Let's read both names and words files.
    NSString *namesString = [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames" encoding:NSUTF8StringEncoding error:NULL];
    
    NSString *wordsString = [NSString stringWithContentsOfFile:@"/usr/share/dict/words" encoding:NSUTF8StringEncoding error:NULL];
    
    //Let's break them down into an array of strings
    NSArray *names = [namesString componentsSeparatedByString:@"\n"];
    NSArray *words = [wordsString componentsSeparatedByString:@"\n"];
    
    //This loop first goes through the names, then goest through the words.
    //Then it compares the two. (though the condition for TRUE is that they
    //must not be exactly equal (as to prevent name to name matching).
    //If condition is true, print both the name and the word.
    
        for (NSString *nombre in names) {
        for (NSString *palabra in words) {
            if (([nombre caseInsensitiveCompare:palabra]==NSOrderedSame) && ([nombre isNotEqualTo: palabra])) {
                NSLog(@"\n  %@ =  %@", nombre, palabra);
            }
        }
    }
}[/code]

#14

hi!first i want thank for this simple good book!it really fun for me,and this my challenge for 15.2

[code]//
// main.m
// 15.2 GroceriesAnddictFind
//
// Created by Sen on 6/12/14.
// Copyright © 2014 SLboat. All rights reserved.
//
// [[Objective-C 编程 By Aaron Hillegass]],P90
//

#import <Foundation/Foundation.h>
#import “main.h”

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

@autoreleasepool {
    // 购物清单...
    Groceries();
    
    takeBreak(); //歇一会..
    
    // 突然小想法猫在这里,嘿,小想法,不错的一个-*-
    // 读入文件保存到字符串(无异常处理),读取文本!!这里读取的是名字是?
    NSString *nameString = [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames" encoding:NSUTF8StringEncoding error:NULL]; // 送入NULL,空处理...

    // 以换行切割字符串
    NSArray  *names  = [nameString componentsSeparatedByString:@"\n"];
    NSString *lookto = @"AA";
    // 枚举出来每一项,names可以用中间的?
    for (NSString *n in names) {
        // 查找特定字符串,忽略大小写,Insensitive
        NSRange r = [n rangeOfString:lookto options:NSCaseInsensitiveSearch];

        //找到了它不
        if (r.location != NSNotFound) {
            // 这里包含的对象是n:)
            NSLog(@"%@包含了%@", n, lookto);
        }
    }
    
    takeBreak();
    // 不可思议,只是串阿串在一起,然后就读取了文件,检查了字符串....

    // 一个简单的展示....搜索字符串
    NSLog(@"hello中的ll位于第%lu个字符开始", [@"hello" rangeOfString: @"ll"].location);

    // 比较字符串的各种方式
    NSString *a = @"ABC";
    NSString *b = @"abcd";
    if ([a caseInsensitiveCompare:b] == NSOrderedSame) {
        NSLog(@"%@ and %@ are eaual", a, b);
    }
    if ([a caseInsensitiveCompare:b] == NSOrderedAscending) {
        NSLog(@"(a)%@ come before (b)%@", a, b);
    }
    if ([a caseInsensitiveCompare:b] == NSOrderedDescending) {
        NSLog(@"b(%@) come before a(%@)", b, a);
    }
    
    takeBreak();
    
    // 最后的事情...找到属于两个文件的存在的东西...
    NSString *propernameStr = [ NSString stringWithContentsOfFile:@"/usr/share/dict/propernames" encoding:NSUTF8StringEncoding error:nil];
    NSString *wordsStr      = [NSString stringWithContentsOfFile:@"/usr/share/dict/words" encoding:NSUTF8StringEncoding error:NULL];
    NSArray  *properArray   = [propernameStr componentsSeparatedByString:@"\n"]; //总是components开头,哈
    NSArray  *wordsArray    = [wordsStr componentsSeparatedByString:@"\n"];
    // 接下来遍历对比
    for (NSString *perProperName in properArray) {
        for (NSString *perWords in wordsArray) {
            if ([perProperName caseInsensitiveCompare] == NSOrderedSame && [perProperName compare]) { //AARON排在几乎第一个...哈
                // 这是一样
                NSLog(@"%@和%@它们都存在!", perProperName, perWords);//objc的字符串常量总是带着@,小老鼠,小邮件符号.
                break; //退出内层循环,退出最外层看起来得抛异常?(如果是Python的话)
            }
        }
    }

}
return 0;

}

/**

  • 一个购物清单数组
    */
    void Groceries(){
    // 在这里看起来某种习惯的变量命名是,首字母小写,中间大写
    NSMutableArray *theList = [NSMutableArray array];
    [theList addObject:@“Eggs”]; //添加字符串它可以的!
    [theList addObject:@“Vegetables”];
    [theList addObject:@“beaon”];

    for (NSString *item in theList) {
    NSLog(@“买下 %@”, item);
    }
    }

/**

  • 歇息一下,一个下划线…
    */
    void takeBreak(){
    printf("\n----\n\n");
    }[/code]

[code]//
// main.h
// 15.2 GroceriesAnddictFind
//
// Created by Sen on 6/13/14.
// Copyright © 2014 SLboat. All rights reserved.
//

//为了防止重复定义!所以这样做!
#ifndef _5_2_GroceriesAnddictFind_main_h
#define _5_2_GroceriesAnddictFind_main_h

void Groceries();
void takeBreak();

#endif[/code]


#15

my solution

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

@autoreleasepool {
    
    // on lis les fichiers
    NSString *chaineDeNoms = [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames" encoding:NSUTF8StringEncoding error:NULL];
    
    NSString *chaineNomsCommuns = [NSString stringWithContentsOfFile:@"/usr/share/dict/words" encoding:NSUTF8StringEncoding error:NULL];
    
    
    // on decompose les chaines  en tableau
    NSArray *noms = [chaineDeNoms componentsSeparatedByString:@"\n"];
    NSArray *nomsCommuns = [chaineNomsCommuns componentsSeparatedByString:@"\n"];
    
    //on parcoure les tableaux
    for (NSString *a in noms) {
        for (NSString *b in nomsCommuns) {
            if ([a caseInsensitiveCompare:b] == NSOrderedSame) {
                if ([a isEqualToString:b]) {
                    NSLog(@"%@ et %@ sont identique",a, b);
                }
                
            }
        }
    }
    
    
    
}
return 0;

}
[/code]