Right now, I have a working app (similar to WhatsApp) where users can do a live search using an NSTextField to add users to a group chat. Using NSPredicate, I search through an array (searchableContacts) to find any available contacts on the app, and like matches are output to a UITableView, like so:
- (void)textFieldDidChange :(UITextField *)theTextField {
[filteredArray removeAllObjects];
NSMutableArray *partPredicates = [NSMutableArray arrayWithCapacity:2];
NSPredicate *currentPartPredicate1 = [NSPredicate predicateWithFormat:#"firstName CONTAINS[cd] %#", self.searchField.text];
NSPredicate *currentPartPredicate2 = [NSPredicate predicateWithFormat:#"lastName CONTAINS[cd] %#", self.searchField.text];
[partPredicates addObject:currentPartPredicate1];
[partPredicates addObject:currentPartPredicate2];
NSPredicate *fullPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:partPredicates];
filteredArray = [[self.searchableContacts filteredArrayUsingPredicate:fullPredicate] mutableCopy];
[self.searchableMembers reloadData];
}
On the resulting tableView, users are able to select users to add to the group. Now, I have an 'addedContacts' array.
When the user goes back into the textField to search for more users to add to the group, how can I alter my NSPredicate to include available contacts (from searchableContacts) that are not already in the group (addedContacts)?
You can simplify the code you have for building the predicate to this:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"firstName CONTAINS[cd] %# OR lastName CONTAINS[cd] %#", self.searchField.text, self.searchField.text];
You can adjust that to exclude the items in addedContacts using this:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(NOT SELF IN %#) AND (firstName CONTAINS[cd] %# OR lastName CONTAINS[cd] %#)", self.addedContacts, self.searchField.text, self.searchField.text];
Related
I'm trying to write a filter with NSPredicate that states:
IF field_Uid contains 47 and field_Target contains 202...display these items
This portion works great. However, I also want to show items in which the reverse is true, eg.:
OR IF fieldUid contains 202 and fieldTarget contains 47...display these
items also
Right now, I have the following code:
NSString *targetedUser = #"47";
NSString *myID = #"202";
NSPredicate *p1 = [NSPredicate predicateWithFormat:#"fieldUid contains[cd] %#", targetedUser];
NSPredicate *p2 = [NSPredicate predicateWithFormat:#"fieldTarget contains[cd] %#", myID];
//E.G. See p3 & p4 being the reverse?
// NSPredicate *p3 = [NSPredicate predicateWithFormat:#"fieldUid contains[cd] %#", myID];
// NSPredicate *p4 = [NSPredicate predicateWithFormat:#"fieldTarget contains[cd] %#", targetedUser];
NSCompoundPredicate *p = [NSCompoundPredicate andPredicateWithSubpredicates:#[p1, p2/*, p3, p4*/]];
NSArray *filtered = [self.messages filteredArrayUsingPredicate:p];
How would I write in the latter? I'm not sure how to do it without making the statement requiring all 4 lines to be true? (See commented out code - I've left it in so you can see what I mean...)
Just combine two compound "and" predicates using a compound "or" predicate.
You have the first compound "and" predicate in your question. Create the 2nd compound "and" predicate as needed.
Now use [NSCompoundPredicate orPredicateWithSubpredicates:] passing in the two "and" compound predicates.
you can also use
NSString *targetedUser = #"47";
NSString *myID = #"202";
//this will easily fix your issue, simply update your query like this
NSPredicate *p = [NSPredicate predicateWithFormat:#"(fieldUid contains[cd] %# AND fieldTarget contains[cd] %#) OR (fieldUid contains[cd] %# AND fieldTarget contains[cd] %#)", targetedUser, myID, myID, targetedUser];
NSArray *filtered = [self.messages filteredArrayUsingPredicate:p];
For example, I have object like #{#"firstName":#"aaa", #"lastName":#"bbb"}.
Now I'm trying to search with next predicate:
NSPredicate *predicateFirstName = [NSPredicate predicateWithFormat:#"firstName contains [c] %#", searchString];
NSPredicate *predicateLastName = [NSPredicate predicateWithFormat:#"lastName contains [c] %#", searchString];
NSPredicate *orPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:#[predicateFirstName, predicateLastName]];
searchUsersArray = [usersArray filteredArrayUsingPredicate:orPredicate];
I need a predicate, which will be return for search string #"aa bb" users whose first name ENDED with "aa" and lastName BEGINS with #"bb"
NSPredicate *predicateLastName = [NSPredicate predicateWithFormat:#"(firstName AND lastName contains [c] %#)", searchString]
don't work for me.
First divide the search string in the end-part and the begin-part:
NSArray *parts = [#"aa bb" componentsSeperatedByString:#" "];
Then use BEGINSWITH and ENDSWITH:
[NSPredicate predicateWithFormat:#"(firstName ENDSWITH[c] %#) AND (lastName BEGINSWITH[c] %#", parts[0], parts[1]];
Alternatively you can add a computed property to the entity concatinating the first name and last name and then search in this property.
Try like this hope it help you
NSString *matchString = [NSString stringWithFormat: #"(.*aa|bb.*)",searchText];
NSString *predicateString = #"keyword MATCHES[c] %#";
NSPredicate *predicate =[NSPredicate predicateWithFormat: predicateString, matchString];
Thanks
Use keyword BEGINSWITH instead of contains.
NSPredicate *predicateFirstName = [NSPredicate predicateWithFormat:#"firstName BEGINSWITH [c] %#", searchString];
NSPredicate *predicateLastName = [NSPredicate predicateWithFormat:#"lastName BEGINSWITH [c] %#", searchString];
I have an array of objects with name and address.
Both properties are of type NSString.
But when i'm using the compound predicate with both results i don't get any result. If i'm using just one predicate it works very well.
Has anyone an idea whats going wrong here in my code? thnx
-(void)filterContentForSearchString:(NSString*) searchText
{
NSPredicate *resultsPredicate = [NSPredicate predicateWithFormat:#"SELF.name like[cd] %#", searchText];
NSPredicate *resultsPredicate2 = [NSPredicate predicateWithFormat:#"SELF.place like[cd] %#", searchText];
NSPredicate *compoundpred = [NSCompoundPredicate andPredicateWithSubpredicates:#[resultsPredicate, resultsPredicate2]];
self.searchResults = [self.companies filteredArrayUsingPredicate:compoundpred];
}
Can you try using a single predicate declaration
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"SELF.name like[cd] %# OR SELF.place like[cd] %#", searchText, searchText];
and filter the array with it directly
self.searchResults = [self.companies filteredArrayUsingPredicate:predicate];
What I do:
NSPredicate *predicate = [NSPredicate predicateWithFormat:
#"SELF.street contains[c] %# OR SELF.id contains[c] %#", searchText];
self.filteredItems = [NSMutableArray arrayWithArray:
[self.items filteredArrayUsingPredicate:predicate]];
I want to check if the given searchText is either in ID or in STREET property. STREET alone works, however as soon as I add the ID check my app crashes.
Any idea how to have both checks for ID and STREET ind the predicate?
You're using %# twice, but only providing one argument, try:
NSPredicate *predicate = [NSPredicate predicateWithFormat:
#"SELF.street contains[c] %# OR SELF.id contains[c] %#", searchText, searchText];
I changed ID from NSNumber to NSString. Now it works.
[filteredArray filterUsingPredicate:
[NSPredicate predicateWithFormat:#"self BEGINSWITH[cd] %#", searchText]];
filteredArray contains simple NSStrings. [hello, my, get, up, seven, etc...];
It will give all strings that begin with searchText.
But if string will be a combination of words like "my name is", and searchText = name. What would a NSPredicate look like to achieve this?
UPDATE:
And how would it have to be if i want to a result with searchText = name, but not with searchText = ame? Maybe like this:
[filteredArray filterUsingPredicate:
[NSPredicate predicateWithFormat:
#"self BEGINSWITH[cd] %# or self CONTENTS[cd] %#",
searchText, searchText]];
But it should first display the strings that begin with searchText and only after those which contain searchText.
[NSPredicate predicateWithFormat:#"self CONTAINS[cd] %#", searchText];
EDIT after expansion of question
NSArray *beginMatch = [filteredArray filteredArrayUsingPredicate:
[NSPredicate predicateWithFormat:
#"self BEGINSWITH[cd] %#", searchText]];
NSArray *anyMatch = [filteredArray filteredArrayUsingPredicate:
[NSPredicate predicateWithFormat:
#"self CONTAINS[cd] %#", searchText]];
NSMutableArray *allResults = [NSMutableArray arrayWithArray:beginMatch];
for (id obj in anyMatch) {
if (![allResults containsObject:obj]) {
[allResults addObject:obj];
}
}
filteredArray = allResults;
This will have the results in the desired order without duplicate entries.
EDIT Actually beginsWith check from start of string to search string length. if exact match found then its filtered
if u have name game tame lame
search Text : ame
filtered text would be: none
contains also check from start of string to search string length but if found start, middle or end exact search string then it is filtered.
if u have name game tame lame
search Text : ame
filtered text would be: name game tame lame because all has ame
[NSPredicate predicateWithFormat:#"self CONTAINS '%#'", searchText];