mnort9
mnort9

Reputation: 1820

NSSortDescriptor and NSPredicate for sorting and filtering

I have a tableView that has 5 different possible datasources depending on a flag object (NSNumber *)dataSourceAssignment. I've implemented an NSSortDescriptor that sorts dataSource by a (float)confidenceRating.

After the datasource is assigned, I need to be able to filter the dataSource array by a (NSString *)genre. I understand how to use NSPredicate to filter my array, but I can't figure out how to do it efficiently when there are 5-6 different genre strings that could be checked.

The user is able "check" multiple genres that should basically toggle the display of tracks according to which genres are selected. I was thinking of creating a dictionary in NSUserDefaults *defaults that would look something like this: ["genre1" = YES, "genre2" = NO, "genre3" = YES ...].

How can I set up NSPredicate to filter datasource using the genre dictionary without using a huge if/switch statement with loads of conditions.

Here is the code I have before a NSPredicate is implemented:

- (void)assignDataSource
{
switch (dataSourceAssignment.intValue) {
    case 0:     dataSource = [NSMutableArray arrayWithArray:tracksArray];           break;
    case 1:     dataSource = [NSMutableArray arrayWithArray:favoriteTracks];        break;
    case 2:     dataSource = [NSMutableArray arrayWithArray:topTracksOfTheWeek];    break;
    case 3:     dataSource = [NSMutableArray arrayWithArray:topTracksOfTheMonth];   break;
    case 4:     dataSource = [NSMutableArray arrayWithArray:topTracksOfTheYear];    break;
    default:    break;
}

if (dataSourceAssignment.intValue >= 2)  {
    NSSortDescriptor *avgRatingSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"confidenceRating" ascending:NO];
    NSArray *sortDescriptors = [NSArray arrayWithObjects:avgRatingSortDescriptor, nil];
    NSArray *sortedArray = [dataSource sortedArrayUsingDescriptors:sortDescriptors];
    dataSource = [NSMutableArray arrayWithArray:sortedArray];
}

Upvotes: 0

Views: 3010

Answers (2)

sergeyne
sergeyne

Reputation: 1318

You can store which genres were selected into array and then use predicate. You can also remove/add elements when user select/deselect elements.

NSArray *selectedGenresByUser = [NSArray arrayWithObjects:@"genre1",@"genre2", nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat: @"genre in $SELECTED_GENRES"];
predicate = [predicate predicateWithSubstitutionVariables:[NSDictionary dictionaryWithObject:[NSArray arrayWithArray:selectedGenresByUser] forKey:@"SELECTED_GENRES"]];
//then use predicate to filter datasource array( maby you can store all elements in one array)

Upvotes: 1

NeonBlueHair
NeonBlueHair

Reputation: 1169

When you use predicateWithFormat, you can pass it a regular expression statement about the predicate. That string is where you can do multiple predicates, and so that can be what you alter when different genres are selected.

For example, you can have: predicateWithFormat:predicateString, and then have predicateString set to be something along the lines of "SELF beginswith genre1 AND SELF beginswith genre1" if the user has selected genre1 and genre2. Though definitely doublecheck that regex I used, cause you need something better than that for it to work well.

Upvotes: 1

Related Questions