Joseph Toronto
Joseph Toronto

Reputation: 1892

Filter NSArray with NSPredicate inexact/similar match?

I have an NSArray of 5 NSArrays that each contain NSDictionaries. The dictionaries contain only strings. I'm trying to use NSPredicate to filter out particular dictionaries, however it only seems to work with an exact match. I would like for it to ignore any punctuation such as : or -. Here's what I have currently.

NSString *seriesTitle = @" Fullmetal Alchemist Brotherhood - ";
NSPredicate *titlePredicate = [NSPredicate predicateWithFormat:
                                   @"series_title CONTAINS[cd]%@", seriesTitle];
NSArray *filtered = [arraytoEvaluate filteredArrayUsingPredicate:titlePredicate]

Within "arraytoEvaluate" is an NSDictionary containing this key-value pair @"series_title" : @"Fullmetal Alchemist: Brotherhood". That's the one I want it to match to. My predicate does not pick this up even though I'm requesting a [cd] search, which I believe ignores punctuation/whitespace, correct?

Using series_title LIKE[cd]%@gives me this crash:

'NSInvalidArgumentException', reason: 'Can't do regex matching on object

Using BEGINSWITH instead gives me this: 'NSInvalidArgumentException', reason: 'Can't do a substring operation with something that isn't a string

If I pass in the string exactly, it will pick it up and give me the the Array that contains the dictionary that contains a match, but only if the search term is an exactly match.

Also, it will give me all of them, not an NSArray containing the single NSDictionary that contains a match. I'm not sure what to do about that. I understand that filteredArrayUsingPredicate is supposed to return an Array, but I will then need to iterate through that Array for the specific NSDictionary that contains a match for the search terms. That's a secondary issue however. Any help would be greatly appreciated.

Upvotes: 0

Views: 1805

Answers (1)

CRD
CRD

Reputation: 53000

You have two problems (a) the match is wrong and (b) you have nested arrays.

(a) [cd] means ignore case and diacritics, not punctuation and whitespace. A solution here is to use a regular expression and MATCHES[CD] as the predicate. You need a regular expression which will match the terms you are looking for. A basic re is:

@"fullmetal[^a-z]*alchemist[^a-z]*brotherhood"

where [^a-z]* matches zero or more (*) characters from the set [...] of every character which is not (^) a letter a-z.

While this works it probably matches far more than you wish - you should refine the regular expression.

(b) The error you got Can't do regex matching on object... is because you cannot match a regular expression against an array, and the elements of your array are themselves array. You can address this using a simple loop over the elements, something along the lines of:

NSMutableArray *filtered = [NSMutableArray new];                                          // allocate an empty mutable array in which to accumulate the matches
for(NSArray *subArray in arraytoEvaluate)                                                 // loop over each sub array
   [filtered addObjectsFromArray:[subArray filteredArrayUsingPredicate: titlePredicate]]; // and perform the predicate

HTH

Upvotes: 3

Related Questions