Amazon.com Widgets My solution for 15.3
Welcome, Guest. Please login or register.
Did you miss your activation email?
April 20, 2014, 10:44:31 PM
Home Help Search chat Login Register 
News: Read this please.The Great Kangaroo Escape Looking for reviews of the 4th ed on Amazon!   Twitter:  @skochan
                     

+ Official Forum for Programming in Objective-C (the iPhone Programming Language) - Stephen Kochan
|-+ Programming in Objective-C, 4th edition
| |-+ Exercises
| | |-+ Chapter 15
| | | |-+ My solution for 15.3
Pages: [1] 2 Go Down
Print
Author Topic: My solution for 15.3 (Read 1939 times)
jgelling
Newbie
*
Posts: 27






on: January 04, 2012, 11:14:19 PM

These forums are a bit bare, and since Carl seems to have stopped posting his work, I thought I'd contribute my solution for 15.3, developed with help from stackoverflow, which I've found has correct answers for just about any basic programming challenge:

Quote
-(NSArray *) lookup:(NSString *)theName
{
    NSMutableArray *matchesFound = [[NSMutableArray alloc] init];
   
    for (AddressCard *nextCard in book)
    {
        if ([[nextCard name] rangeOfString:theName options:(NSCaseInsensitiveSearch)].location == NSNotFound){ //rangeOf methods return an NSRange where the match is found, if the substring isn't found, it returns "NSNotFound"; the NSCaseInsensitiveSearch option does what it says - since there's no match there's nothing to do here
        }

        else {
            [matchesFound addObject:nextCard]; //if NSRange is NOT NSNotFound, we have a match - add to matchesFound array
        }
    }
   
    if ([matchesFound count] > 0) //count reflects the size of the array, >0 if match found
    {
        return matchesFound;
    }
   
    return nil;
}
Last Edit: January 04, 2012, 11:18:07 PM by jgelling Logged
bcharna
Newbie
*
Posts: 9






Reply #1 on: January 07, 2012, 12:28:17 PM

I would change the method signature to return NSMutableArray or just convert the mutable array to a new NSArray just so the user of the method knows what they are getting and so they don't unnecessarily make an NSMutableArray out of what your method returns.   Looks good otherwise.  Here is mine (I should have used CaseInsensitiveSearch instead for readability).

Code: (Objective-C)
-(NSMutableArray *) lookup: (NSString *) theName 
{
    NSMutableArray *matches = [NSMutableArray array];
    theName = [theName lowercaseString];
    for ( AddressCard *nextCard in book )
        if ( [[nextCard.name lowercaseString] rangeOfString: theName].location != NSNotFound )
            [matches addObject: nextCard];
   
    if ([matches count] == 0)
        return nil;
    else
        return matches;
}
Logged
jgelling
Newbie
*
Posts: 27






Reply #2 on: January 07, 2012, 03:04:31 PM

Yeah, you can get away with declaring NSArray as the return type for an NSMutableArray because NSMutableArray is a sub-class of NSArray.

I returned an NSArray because I can't imagine any situation in which you'd want to modify the results of lookup after the array has been returned.

In general, I think it's better practice to work with immutable objects when mutability isn't strictly necessary. Mutable objects use more memory, and of course have the potential of being accidentally changed.

But you're right though, I should have done an explicit conversion. This requires declaring a new NSArray as a copy. That's the only way to return a real, separate NSArray from an NSMutableArray.

Still the original code should prohibit treating the return type from lookup as a mutable array, which is half the battle. I didn't check it, but I assume if I tried to addObject or removeObject, e.g. to an array returned from lookup the compiler should complain. I think that's still better than returning a mutable array unnecessarily, but I should have coded it cleaner.
Last Edit: January 07, 2012, 10:16:05 PM by jgelling Logged
mitchb
Full Member
***
Posts: 128






Reply #3 on: January 07, 2012, 08:45:22 PM

I went about this a little differently. My thought was to just create a new address book and call it matches, this way I could use the -addCard, -list, and -entries methods. This method also searches both name and email strings.

Code: (Objective-C)
- (AddressBook *) lookupAll: (NSString *) theName
{
    AddressBook *match = [[[AddressBook alloc] initWithName: @"Matches"] autorelease];
   
    for( AddressCard *nextCard in book )
    {
        if( [nextCard.name  rangeOfString: theName options: NSCaseInsensitiveSearch].location != NSNotFound ||
            [nextCard.email rangeOfString: theName options: NSCaseInsensitiveSearch].location != NSNotFound )
        {
            [match addCard: nextCard];
        }
    }
    if ( [match  entries] > 0 )
        return  match;
    else
        return nil;
}

2012-01-07 18:30:27.528 AddressBook[245:903] Lookup "j"
2012-01-07 18:30:27.530 AddressBook[245:903]          Contents of: Linda's Address Book
2012-01-07 18:30:27.531 AddressBook[245:903] ====================================================
2012-01-07 18:30:27.531 AddressBook[245:903] Julia Kochan            jewls337@axlc.com               
2012-01-07 18:30:27.532 AddressBook[245:903] Tony Iannino            tony.iannino@techfitness.com   
2012-01-07 18:30:27.532 AddressBook[245:903] Stephen Kochan          steve@classroom.com             
2012-01-07 18:30:27.533 AddressBook[245:903] Jamie Baker             jbaker@classroom.com           
2012-01-07 18:30:27.533 AddressBook[245:903] ====================================================
2012-01-07 18:30:27.534 AddressBook[245:903]          Contents of: Matches
2012-01-07 18:30:27.534 AddressBook[245:903] ====================================================
2012-01-07 18:30:27.535 AddressBook[245:903] Julia Kochan            jewls337@axlc.com               
2012-01-07 18:30:27.535 AddressBook[245:903] Jamie Baker             jbaker@classroom.com           
2012-01-07 18:30:27.536 AddressBook[245:903] ====================================================

Mitch
Logged

If you give a man a program, you will frustrate him for a day;
If you teach him how to program, you will frustrate him for a lifetime;
     - Anonymous
alexsom
Jr. Member
**
Posts: 63



Email




Reply #4 on: February 22, 2012, 08:18:45 AM

It looks like everyone is running away from NSIndexSet class. I wonder why....
Logged
mitchb
Full Member
***
Posts: 128






Reply #5 on: February 22, 2012, 10:50:47 AM

Take a look at this link.

http://classroomm.com/objective-c/index.php?topic=6715.msg18336#msg18336

Mitch
Logged

If you give a man a program, you will frustrate him for a day;
If you teach him how to program, you will frustrate him for a lifetime;
     - Anonymous
alexsom
Jr. Member
**
Posts: 63



Email




Reply #6 on: February 22, 2012, 11:06:33 AM

ahh...come on man. you have to use as a start exactly this method:

-(NSIndexSet *) lookupAll: (NSString *) theName

What the guy did with the other one is twisting  a little the solution
NSMutableArray *lookupAll = [NSString *) theName; from page 363

good effort but it doesn't fulfill the requirement.
Logged
GenyTales
Newbie
*
Posts: 13






Reply #7 on: February 26, 2012, 09:58:33 AM

No.
Exercise 3 says at the bottom:

"(Note that the example presented at the end of this chapter returns an NSIndexSet result, but we want an array of AddressCards here.)"

So we have to use
-(NSMutableArray *) lookupAll = (NSString *) theName;
because we need to return an array.

Also one more thing that seems anybody is not doing is what says on page 364:

"It's left as an exercise for you... (Hint: After the indexesOfObjectsPassingTest: method is done, enumerate each index for the index set and add the corresponding element to an array that you'll return.)"

So one (and maybe the best) solution is the one linked by mitchb because it has all that the exercise asks.
Logged
alexsom
Jr. Member
**
Posts: 63



Email




Reply #8 on: February 26, 2012, 10:56:59 AM

Voila, you just said it in the hint: how you convert an NSIndexSet result into an array type AddressCards result, and not starting with a method that already returns that. It's relatively simple for people who think Objective-C, not me who just scratch the surface. I'm out.
Logged
Hesadanza
Newbie
*
Posts: 28






Reply #9 on: February 26, 2012, 12:57:33 PM

Here's my lookupAll method that uses NSIndexSet.  It got a little tricky when turning the NSIndexSet back into an array of cards, since you can't use typical enumeration.  You have to use method with a block to enumerate on it.

Code: (Objective-C)
-(NSMutableArray *) lookupAll: (NSString *) theName
{
    //Find indexes in the address book that match the search term
    NSIndexSet *indexResults = [book indexesOfObjectsPassingTest:
        ^(id obj, NSUInteger idx, BOOL *stop) {
            NSRange subrange;
           
            //first check to see if the search term matches anything in the name
            subrange = [[obj name] rangeOfString:theName options:NSCaseInsensitiveSearch];
            if (subrange.location != NSNotFound)
                return YES;
           
            //then check to see if the search term matches anything in the email address
            subrange = [[obj email] rangeOfString:theName options:NSCaseInsensitiveSearch];
            if (subrange.location != NSNotFound)
                return YES;
           
            // Nothing found.
            else return NO;
        }];
    NSMutableArray *cardsResults;
   
    //Put the found address cards into an array using their indexes.
    if ([indexResults count] > 0)
    {
        cardsResults = [NSMutableArray array];
        [indexResults enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
            [cardsResults addObject:[book objectAtIndex:idx]];
        }];
    }
    return cardsResults;
}
Logged
alexsom
Jr. Member
**
Posts: 63



Email




Reply #10 on: February 26, 2012, 02:40:23 PM

Excellent job and variety is always welcomed, but try to start with this method:

-(NSIndexSet *) lookupAll: (NSString *) theName

and turn it into an AddressCard result. If you were able to do it the other way I'm sure you can make this happened. Give a try. Thanks
Logged
Hesadanza
Newbie
*
Posts: 28






Reply #11 on: February 26, 2012, 03:45:38 PM

Why would I want to do that?  That's not what the exercise calls for.

In any case, I would just truncate the last portion of my method, return indexResults, and do the rest in main.  But we might as well do all that work directly in the method.  No need to return the index set.
Logged
alexsom
Jr. Member
**
Posts: 63



Email




Reply #12 on: February 26, 2012, 03:57:21 PM

Go ahead and make it happen in one method.
Actually that's what the exercise calls for.
Last Edit: February 26, 2012, 04:11:52 PM by alexsom Logged
Hesadanza
Newbie
*
Posts: 28






Reply #13 on: February 26, 2012, 04:01:29 PM

No, it's not.  The exercise says, "Have the method return an array of all such matching address cards, or nil if no match is made."
Logged
GenyTales
Newbie
*
Posts: 13






Reply #14 on: February 27, 2012, 04:54:12 AM

OMG. Alexsom read what the exercise ask. Once again:
RETURN an ARRAY not a NSindexSet
Logged
Pages: [1] 2 Go Up
Print
Jump to:



Login with username, password and session length

Powered by MySQL Powered by PHP Powered by SMF 1.1.11 | SMF © 2006-2009, Simple Machines LLC Valid XHTML 1.0! Valid CSS!
Entire forum contents (c) 2009 classroomM.com. All rights reserved.