Bronze Challenge - Is It Possible Using Sorted Array?


#1

Help!

Tried to sort the BRNItem array: allItems, but encountered a problem I didn’t know how to solve:

“this class is not key value coding-compliant for the key valueInDollars.”

valueInDollars is integer typed. Is it the reason?

Has anyone tried using sorted array to conquer this challenge?


#2

Hi James,
Here is my solution using a sorted array.

Count the number of rows that should be displayed in each section.

- (NSInteger)tableView:(UITableView *)tableView 
 numberOfRowsInSection:(NSInteger)section
{
    NSInteger rowCount;
    NSPredicate *lessThan50Predicate = [NSPredicate predicateWithFormat:@"SELF.valueInDollars < 50"];
    NSPredicate *moreThan50Predicate = [NSPredicate predicateWithFormat:@"SELF.valueInDollars >= 50"];
    NSArray *itemsLessThan50;
    NSArray *itemsMoreThan50;
    
    if (section == 0) {
        itemsLessThan50 = [[[BNRItemStore sharedStore] allItems] filteredArrayUsingPredicate:lessThan50Predicate];
        rowCount = [itemsLessThan50 count];
    } else if (section == 1) {
        itemsMoreThan50 = [[[BNRItemStore sharedStore] allItems] filteredArrayUsingPredicate:moreThan50Predicate];
        rowCount = [itemsMoreThan50 count];
    }
    
    return rowCount;
}

Sort the items in the array, this will return a new array.
In the new array, find the index of the first item with the value more than 50.
Calculate the position of the next rows by adding to the index of the found row.

- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Check for a free cell first and reuse it
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
    
    if (!cell) {
        // Create an instance of UITableViewCell, with default appearence
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                      reuseIdentifier:@"UITableViewCell"];
    }
    
    // Sort the items first
    NSArray *sortedArray = [[[BNRItemStore sharedStore] allItems] sortedArrayUsingComparator: ^(id obj1, id obj2) {
        if ([obj1 valueInDollars] > [obj2 valueInDollars]) {
            return (NSComparisonResult)NSOrderedDescending;
        }
        
        if ([obj1 valueInDollars] < [obj2 valueInDollars]) {
            return (NSComparisonResult)NSOrderedAscending;
        }
        
        return (NSComparisonResult)NSOrderedSame;

    }];
    
    
    // Set the text on the cell with the description of the item that is at the nth index
    // of items
    
    NSInteger row;
    if ([indexPath section] == 0) {
        row = [indexPath row];
    } else {
        row = [sortedArray indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
            return [obj valueInDollars] >= 50;
        }];
        row = row + [indexPath row];
        
    }
    
    BNRItem *p = [sortedArray objectAtIndex:row];
    
    [[cell textLabel] setText:[p description]];
    
    return cell;
}

#3

OK, so here’s my solution which doesn’t use the NSPredicate method but involves first of all writing a method to sort the allItems Array of BNRItems in BNRItemStore.m:

-(NSArray *)sortItems { NSSortDescriptor *vid = [NSSortDescriptor sortDescriptorWithKey:@"valueInDollars" ascending:YES]; [allItems sortUsingDescriptors:[NSArray arrayWithObjects:vid, nil]]; return allItems; }

Then a method to count the number of items in each category (>50 and <50 dollars in value):

-(NSInteger)countItemsInSection:(NSInteger)sectionIndex; { NSInteger countOfItemsInSection = 0; if (sectionIndex == 0) { for (int i = 0; i < [allItems count]; i++) { if ([[allItems objectAtIndex:i] valueInDollars] < 50) countOfItemsInSection ++; } } else if (sectionIndex ==1) { for (int i = 0; i < [allItems count]; i++) { if ([[allItems objectAtIndex:i] valueInDollars] > 50) countOfItemsInSection ++; } } return countOfItemsInSection; }

Then I modify the -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method in ItemsViewController.m:

[code]-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Check for a reusable cell first, use that if it exists
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@“UITableViewCell”];

//If there is no resuable cell, create a new one
if(!cell) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"];
}

if ([indexPath section] == 0) {
    BNRItem *p = [[[BNRItemStore sharedStore] allItems] objectAtIndex:[indexPath row]];
    [[cell textLabel] setText:[p description]];
} else if ([indexPath section] == 1) {
    BNRItem *p = [[[BNRItemStore sharedStore] allItems] objectAtIndex:([indexPath row] + [[BNRItemStore sharedStore] countItemsInSection:1] + 1)];
    [[cell textLabel] setText:[p description]];
}

return cell;

}[/code]

And that’s it. It works well but it is not, admittedly, capable of coping with a general case.

I’m a real novice so any feedback is much appreciated!!

Thanks

James