Solution to final challenge without nesting


#1

I haven’t benchmarked any of the solutions thus far, but here’s a way to solve it without a nested loop (well, at least not explicitly!)

I’m curious (but too tired) to find out if this is faster or slower than the solutions that nest (and therefore iterate) over the loops manually. I.e., I realize that the indexOfObject message is doing some sort of search, but wonder if it is more efficient than a brute search through the list.

        NSString *nameString = [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames"
                                encoding:NSUTF8StringEncoding error:NULL];
        
        NSString *wordsString = [NSString stringWithContentsOfFile:@"/usr/share/dict/words"
                                                         encoding:NSUTF8StringEncoding error:NULL];
        
        NSArray *nameArr = [nameString componentsSeparatedByString:@"\n"];
        NSMutableArray *wordsArr = (NSMutableArray*)[wordsString componentsSeparatedByString:@"\n"];
                
        int count=0;

        for(NSString* name in nameArr)
        { 
            // see if there is a lower case version
            NSString* lowerCaseName = [name lowercaseString];
            NSInteger foundIndexOfLowerCaseWord = [wordsArr indexOfObject:lowerCaseName];
            if(foundIndexOfLowerCaseWord!=NSNotFound)
            {
                NSLog(@%d "%@ %@", ++count, name, [wordsArr objectAtIndex:foundIndexOfLowerCaseWord]);
            }
        }
    }

#2

You can easily find out by using something similar to the following:

main.mm - Objective-C++ (note the .mm suffix):

//  main.mm

#import <Foundation/Foundation.h>
#import "MyTiming.h"

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

    NSString *namesString;
    NSString *wordsString;

    {
        my::timing::ElapsedTime ET ("Code 1");
        namesString = [NSString stringWithContentsOfFile:@"/usr/share/dict/propernames"
                                                         encoding:NSUTF8StringEncoding error:NULL];
    }
    
    {
        my::timing::ElapsedTime ET ("Code 2");
        wordsString = [NSString stringWithContentsOfFile:@"/usr/share/dict/words"
                                                          encoding:NSUTF8StringEncoding error:NULL];
    }
    
    NSArray *nameArr = [namesString componentsSeparatedByString:@"\n"];
    NSArray *wordsArr = [wordsString componentsSeparatedByString:@"\n"];
    
    {
        my::timing::ElapsedTime ET ("Code 3");
        int count=0;
        for (NSString* name in nameArr)
        { 
            // see if there is a lower case version
            NSString* lowerCaseName = [name lowercaseString];
            NSInteger foundIndexOfLowerCaseWord = [wordsArr indexOfObject:lowerCaseName];
            if (foundIndexOfLowerCaseWord!=NSNotFound)
            {
                NSLog (@"%d %@ %@", ++count, name, [wordsArr objectAtIndex:foundIndexOfLowerCaseWord]);
            }
        }
    }
    }
    return 0;
}

MyTiming.h - C++ code:

// MyTiming.h

#ifndef MY_TIMING_H
#define MY_TIMING_H

#include <iostream>
 #include <sys/resource.h>

namespace my {
    namespace timing {
        struct ElapsedTime
        {
            rusage t1;
            
            std::string what;
            bool autoPrint;
            std::ostream &os;
            
            ElapsedTime (const std::string &what, bool autoPrint = true)
               : what (what), autoPrint (autoPrint), os (std::cout)
            {
                getrusage (RUSAGE_SELF, &t1);
            }
            
            ElapsedTime (const std::string &what, std::ostream &os, bool autoPrint=true)
                : what (what), autoPrint (autoPrint), os (os)
            {
                getrusage (RUSAGE_SELF, &t1);
            }
            
            ~ElapsedTime ()
            {
                if (autoPrint) Print (os);
            }
            
            double Value () const
            {
                rusage t2;
                getrusage (RUSAGE_SELF, &t2);
                double v = double (1000000) * double (t2.ru_utime.tv_sec - t1.ru_utime.tv_sec)
                           + double (t2.ru_utime.tv_usec - t1.ru_utime.tv_usec);
                return v;
            }
            
            void Print () const
            {
                Print (os);
            }
            
            void Print (std::ostream &os) const
            {
                os << "--- " << what << " - spent time: " << Value() << " microseconds" << std::endl;
            }
        };
    }
}
#endif

The console output:

--- Code 1 - spent time: 92 microseconds
--- Code 2 - spent time: 324 microseconds
2012-06-02 16:19:25.953 TimingBenchmark[17964:503] 1 Al al
2012-06-02 16:19:25.971 TimingBenchmark[17964:503] 2 Alan alan
2012-06-02 16:19:26.069 TimingBenchmark[17964:503] 3 Alf alf
...
2012-06-02 16:19:43.004 TimingBenchmark[17964:503] 293 Woody woody
2012-06-02 16:19:43.041 TimingBenchmark[17964:503] 294  
--- Code 3 - spent time: 1.60632e+07 microseconds

#3

The other way to solve it without doing double for loops that came to my mind is to create a function inside the first loop (that accepts an array and a string and then does a comparison inside the function and returns something)