David P
David P

Reputation: 617

How to join two strings for NSPredicate, ie firstname and lastname

I have a Person Object which has two NSString properties; firstName and lastName. I'm currently using an NSPredicate like so:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(firstName contains[cd] %@) OR (lastName contains[cd] %@)", searchText, searchText];

So, for example, say I'm searching for the name "John Smith". In my search bar if I type "Joh", then John Smith will appear as an option. This is good and fine, but if I type in "John Sm" it will go blank.

How can I join firstName and lastName in the predicate so if I was searching for "John Sm" then John Smith would still appear as an option.

I hope this makes sense. Thanks.

EDIT: To add a bit more clarification, I'm using the SearchDisplayController delegate method:

-(void)filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope;

and I'm using the predicate like so:

newArray = [personObjectArray filteredArrayUsingPredicate:predicate];

Upvotes: 15

Views: 4806

Answers (3)

jjc2661
jjc2661

Reputation: 51

The solution suggested above will not work with search strings that have more than two words. Here is a more thorough implementation in swift. This solution also allows for adding more fields on a record, if your goal is to implement a full text search across name, email, phone number, etc. In that case just update the NSPredicate to OR newField CONTAINS[cd] %@ and be sure to add the extra $0 in the list of string replacements.

let searchText = search.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
let words = searchText.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
let predicates = words.map { NSPredicate(format: "firstName CONTAINS[cd] %@ OR lastName CONTAINS[cd] %@", $0,$0) }

let request = NSFetchRequest()
request.predicate = NSCompoundPredicate(type: NSCompoundPredicateType.AndPredicateType, subpredicates: predicates)

Upvotes: 4

poyo fever.
poyo fever.

Reputation: 752

you can concatenate the fields into two common fields (firstLastName and lastFirstName )

- (NSString *)firstLastName {
      return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}

- (NSString *)lastFirstName {
      return [NSString stringWithFormat:@"%@ %@", self.lastName, self.firstName];
}

and then filter on this fields using 'contains[cd]'

[NSPredicate predicateWithFormat:@"(firstLastName contains[cd] %@) OR (lastFirstName contains[cd] %@)" , self.searchBar.text, self.searchBar.text];

Upvotes: 1

iDev
iDev

Reputation: 23278

Try this,

NSString *text = @"John Smi";
NSString *searchText = [text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];

NSArray *array = [searchText componentsSeparatedByString:@" "];
NSString *firstName = searchText;
NSString *lastName = searchText;
NSPredicate *predicate = nil;

if ([array count] > 1) {
    firstName = array[0];
    lastName = array[1];
    predicate = [NSPredicate predicateWithFormat:@"(firstName CONTAINS[cd] %@ AND lastName CONTAINS[cd] %@) OR (firstName CONTAINS[cd] %@ AND lastName CONTAINS[cd] %@)", firstName, lastName, lastName, firstName];
} else {
    predicate = [NSPredicate predicateWithFormat:@"firstName CONTAINS[cd] %@ OR lastName CONTAINS[cd] %@", firstName, lastName];
}

NSArray *filteredArray = [people filteredArrayUsingPredicate:predicate];
NSLog(@"%@", filteredArray);

Output:

(
        {
        firstName = John;
        lastName = Smith;
    }
)

Here text represents the searched text. The advantage with the above is, even if you pass text = @"Smi Joh"; or text = @"John "; or text = @" smi"; or text = @"joh smi ";, it will still show the above output.

Upvotes: 20

Related Questions