NSPredicate: Combine CONTAINS with IN

后端 未结 4 813
庸人自扰
庸人自扰 2020-11-29 09:42

I have a set of users in CoreData and an search field in my application. User has the properties firstname and name.

Currently I have a predicate like \"user.name CO

相关标签:
4条回答
  • 2020-11-29 10:15

    I don't think that you can combine "IN" with "CONTAINS" in a predicate. But you could split the search string into words, and create a "compound predicate":

    NSString *searchString = @"John  Sm ";
    NSArray *words = [searchString componentsSeparatedByString:@" "];
    NSMutableArray *predicateList = [NSMutableArray array];
    for (NSString *word in words) {
        if ([word length] > 0) {
            NSPredicate *pred = [NSPredicate predicateWithFormat:@"user.name CONTAINS[c] %@ OR user.firstname CONTAINS[c] %@", word, word];
            [predicateList addObject:pred];
        }
    }
    NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicateList];
    NSLog(@"%@", predicate);
    

    This example produces the predicate

    (user.name CONTAINS[c] "John" OR user.firstname CONTAINS[c] "John") AND
    (user.name CONTAINS[c] "Sm" OR user.firstname CONTAINS[c] "Sm")
    

    which would match "John Smith", but not "John Miller".

    0 讨论(0)
  • 2020-11-29 10:18

    I had the same problem and solved it like this:

    In my NSManagedObject class (user) I added the following method, merging the two values into a single string:

    - (NSString *)name
    {
        return [NSString stringWithFormat:@"%@ %@", self.firstname, self.lastname];
    }
    

    Then you'll only need the following lines to match against your list, which is in my case an NSArray with user objects:

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name contains[c] %@", searchString];
    NSArray *filteredUsers = [users filteredArrayUsingPredicate:predicate];
    
    0 讨论(0)
  • 2020-11-29 10:19

    Swift 4 Update:

    let firstName = NSPredicate(format: "firstName CONTAINS[c] %@", searchText)
    let lastName = NSPredicate(format: "lastName CONTAINS[c] %@", searchText)
    
    let orCompoundPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: 
    [firstNamePredicate,lastNamePredicate]
    

    Use the orCompoundPredicate while fetching data.

    0 讨论(0)
  • 2020-11-29 10:25

    2.5 years later I can answer my question with a bit more complex example in swift:

    var predicateList = [NSPredicate]()
    
    let words = filterText.componentsSeparatedByString(" ")
    
    for word in words{
    
         if count(word)==0{
               continue
         }
    
         let firstNamePredicate = NSPredicate(format: "firstName contains[c] %@", word)
         let lastNamePredicate = NSPredicate(format: "lastName contains[c] %@", word)
         let departmentPredicate = NSPredicate(format: "department contains[c] %@", word)
         let jobTitlePredicate = NSPredicate(format: "jobTitle contains[c] %@", word)
    
         let orCompoundPredicate = NSCompoundPredicate(type: NSCompoundPredicateType.OrPredicateType, subpredicates: [firstNamePredicate, lastNamePredicate,departmentPredicate,jobTitlePredicate])
    
         predicateList.append(orCompoundPredicate)
    }
    
    request.predicate = NSCompoundPredicate(type: NSCompoundPredicateType.AndPredicateType, subpredicates: predicateList)
    
    0 讨论(0)
提交回复
热议问题