views:

1401

answers:

2

Long time Windows developer, 1st time Objective-C/iPhone developer wants to create a dictionary of arrays that can be displayed in a plain TableView with alphabetic sections.

The source for this dictionary of arrays is an array containing store names sorted alphabetically:

Apple Store
Atlanta Bread Company
Borders
Build-A-Bear Workshop
Cargill Gallery
Dillards
Dick's Sporting Goods
Eddie Baure
FootLocker
GameStop
Heizberg Diamonds
LensCrafters
McDonald's
Nordstrom
Payless Shoe Source
Pottery Barn
Solstice
Starbucks Coffee
Victoria's Secret
White Barn Candle Co.

The dictionary of arrays that's created from the source should look something like this (datatype in parenthesis):

Root (Dictionary)
....A (Array)
........Apple Store (String)
........Atlanta Bread Company (String)
....B (Array)
........Borders (String)
........Build-A-Bear Workshop (String)
....C (Array)
........Cargill Gallery (String)
....D (Array)
........Dillards (String)
........Dick's Sporting Goods (String)
....etc.

A dictionary of arrays like the above structure populates the TableView and displays like this:

A
Apple Store
Atlanta Bread Company
B
Borders
Build-A-Bear Workshop
C
Cargill Gallery
D
Dillards
Dick's Sporting Goods
etc.

The code I've written that creates the dictionary of arrays ends up putting the last store (White Barn Candle Co.) after every section header.

A
White Barn Candle Co.
B
White Barn Candle Co.
C
White Barn Candle Co.
D
White Barn Candle Co.
etc.

I realize this is happening because I reuse a temporary array, populating it with the A's, clearing it out, populating it with the B's, clearing it out, etc. Here's the actual code that creates the dictionary of arrays from the source array.

NSMutableDictionary *places = [[NSMutableDictionary alloc] init];
NSMutableArray *alphaPlace = [[NSMutableArray alloc] init]; 

for (int x = 1; x <= 26; x++) {
    NSString *alphabet = [[NSString alloc] initWithString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZ"];
    NSString *letter = [alphabet substringWithRange:NSMakeRange(x - 1, 1)];

    for (NSString *place in allPlaces) {
        NSString *first = [place substringWithRange:NSMakeRange(0, 1)];
        if ([first isEqualToString:letter] == YES) { // Add to alphaPlace
            [alphaPlace addObject:place];
        }
        else { // Add alphaPlace to places, clear out alphaPlace; add new item to alphaPlace
            [places setValue:alphaPlace forKey:letter];
            [alphaPlace removeAllObjects];  // SAME ARRAY BEING USED FOR ALL LETTERS OF ALPHABET!
            [alphaPlace addObject:place];
        }
    }
}

I realize I could "brute force" this by creating 26 distinct arrays and using a switch statement to select the correct one to populate but I really don't want to do that. I thought someone more familiar with Objective-C could provide me with a more elegant solution.

Thanks in advance. Let me know if you need more info.

+3  A: 

I think you want to do something like this:

NSMutableDictionary *places = [[NSMutableDictionary alloc] init];

// initialize places with an array for each letter
NSString *alphabet = [[NSString alloc] initWithString:@"ABCDEFGHIJKLMNOPQRSTUVWXYZ"];
for (int x = 0; x < 26; x++) {
    NSString *letter = [alphabet substringWithRange:NSMakeRange(x, 1)];
    [places setObject:[NSMutableArray array] forKey:letter];
}

// then put each place in the array corresponding to its first letter
for (NSString *place in allPlaces) {
    NSString *first = [[place substringWithRange:NSMakeRange(0, 1)] uppercaseString];
    NSMutableArray *letterArray = [places objectForKey:first];
    [letterArray addObject:place];
}
dcrosta
Thanks, that worked like a charm!
billmaya
A: 

Hi,

Thanks for the above solution. I recreated almost exactly the same thing. Now, in the function

(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

I am trying to return the count for a given section, however I am getting a bad access exception in the 3rd line.

NSMutableArray *letterArray = [places objectForKey:[headers objectAtIndex:section]];
NSLog(@"%@",letterArray);
NSLog(@"%@",[letterArray count]);
return [letterArray count];

where headers is a NSMutableArray of titles (its not as simple as an alphabetical list).

RaelG
turns out it was the %@. %d works fine NSLog(@"%d",[letterArray count]);
RaelG