Compare two components by NSPredicate - ios

I want to query an NSDictionary of contacts using NSPredicate. I am able to search the contacts using the "firstName" and "lastName" separately, but I also need to search the contacts whose complete name is entered.
For example: If I want to search a contact with name "John Doe", and I search by entering search key "John" or "Doe", I am able to get the name, but I also want it to be searchable when I enter search key "John Doe". Currently I am using :
NSPredicate *p1 = [NSPredicate predicateWithFormat:#"lastNames BEGINSWITH[cd] %#", searchText];
NSArray *p1FilteredArray = [allContacts filteredArrayUsingPredicate:p1];
NSPredicate *p2 = [NSPredicate predicateWithFormat:#"firstNames BEGINSWITH[cd] %#", searchText];
NSArray *p2FilteredArray = [allContacts filteredArrayUsingPredicate:p2];
searchedArray = [[p1FilteredArray arrayByAddingObjectsFromArray:p2FilteredArray] mutableCopy];

You can use single predicate with or operator:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"firstNames beginswith[cd] %# or lastNames beginswith[cd] %#", searchTerm, searchTerm];
NSArray *results = [allContacts filteredArrayUsingPredicate:predicate];

I would do something like e.g. this:
NSArray *_allContacts = // ...;
NSString *_searchText = // ...;
NSArray *_result = [_allContacts filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(NSDictionary * evaluatedObject, NSDictionary *bindings) {
return ([[[evaluatedObject valueForKey:#"lastNames"] lowercaseString] hasPrefix:[_searchText lowercaseString]] || [[[evaluatedObject valueForKey:#"firstNames"] lowercaseString] hasPrefix:[_searchText lowercaseString]]);
}]];

Related

NSPredicate for custom objects not working

I have array of custom objects, _momsArray. shown here is single object of such array:
Custom *yourMom {
name = #"Sally M. Brown";
age = 54;
weight = 43.2;
}
I run my predicate inside searchBar delegate:
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if ([searchText length]<=0) {
_tableDataArr = [[NSMutableArray alloc] initWithArray:_momsArray];
} else{
// filtered _tableDataArr
NSString *filter = #"name BEGINSWITH[cd] %#";
NSPredicate* predicate = [NSPredicate predicateWithFormat:filter, searchText];
NSArray *filteredArr = [_momsArray filteredArrayUsingPredicate:predicate];
_tableDataArr = [[NSMutableArray alloc] initWithArray:filteredArr];
}
[_momTable reloadData];
}
This doesn't give expected result. For example, when I type S, sally doesn't appear at all. What is wrong with my code?
EDIT: The string in the custom objects contains punctuations and therefore it is not the same as other answers.
To filter an array with custom objects you can use this code.
NSString *str = #"text";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self.name contains[c] %#", str];
NSArray *arrFiltered = [self.arrDataObject filteredArrayUsingPredicate:predicate];
Hope, it helps.
Your string is not properly generated so use below code :
NSPredicate *predicate = [ NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", text];
arrFilterData = [NSArray arrayWithArray:[arrDataList filteredArrayUsingPredicate:predicate]];
OUTPUT
Before search
After search
And with code
NSPredicate *predicate = [ NSPredicate predicateWithFormat:#"SELF CONTAINS[c] %#", text];
arrFilterData = [NSArray arrayWithArray:[arrDataList filteredArrayUsingPredicate:predicate]];
OutPut:
Edit
Output :
Use this code :
NSPredicate *pred = [NSPredicate predicateWithFormat:#"name CONTAINS[cd] %#", searchText];
NSMutableArray *filteredArr = [[_momsArray filteredArrayUsingPredicate:pred]mutableCopy];

Using NSPredicate with NSMutableArray

I'm trying to use the input on an NSTextField along with NSPredicate to populate a NSMutableArray of like objects.
In my app I have the following simple NSMutableArray
{
firstName = Danton;
phoneNumbers = 5555555555;
}
Now, I am using the following code to try and filter the results as the user types (if "Dan" is in the textField, the filtered array should include the above object)
NSMutableArray *filteredArray = [[NSMutableArray alloc] init];
NSPredicate *sPredicate = [NSPredicate predicateWithFormat:#"firstName CONTAINS[cd] %#", self.searchField.text];
filteredArray = [[filteredArray filteredArrayUsingPredicate:sPredicate] mutableCopy];
NSLog(#"Filtered values: %#", filteredArray);
However, I am getting an empty return on filteredArray. Can someone tell me what is wrong with my code?
NSArray *array = #[
#{
#"firstName" : #"Danton", #"phoneNumbers" : #"5555555555"
}
];
NSArray *result = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"%K contains[c] %#", #"firstName", #"Dan"]];

Coredata predicate IN operator with like or contain

I have two arrays on which I have to do the wildcard search and I am using the IN operator but the IN operator gives me the exact matching but I want to fetch all the results that contains the searchTerm. Is this possible through IN operator or do I have to manually loop through all the records and match pick the record that I want.
Current Code :
NSArray *filteredArray = [brandsFabric filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"self.color_name IN %# OR self.subcategory_name IN %#",colorNamesArray,patternNamesArray]];
Desired functionality something like this:
NSArray *filteredArray = [brandsFabric filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"self.color_name IN like/contains %# OR self.subcategory_name IN like/contains %#",colorNamesArray,patternNamesArray]];
This is a very expensive operation, but you can try:
NSMutableArray *predicates = [NSMutableArray array];
for (NSString *name in colorNames) {
[predicates addObject:[NSPredicate predicateWithFormat:
#"color_name CONTAINS[cd] %#", name]];
}
for (NSString *name in subcategoryNames) {
[predicates addObject:[NSPredicate predicateWithFormat:
#"subcategory_name CONTAINS[cd] %#", name]];
}
NSPredicate *final = [NSCompoundPredicate orPredicateWithSubpredicates:predicates];
Maybe even a subquery is in order here. (experimental)
[NSPredicate predicateWithFormat:
#"((SUBQUERY(%#, $x, color_name CONTAINS[cd] $x).#count != 0) OR "
#"((SUBQUERY(%#, $x, category_name CONTAINS[cd] $x).#count != 0)",
colorNames, categoryNames];
It goes like this : CONTAINS[cd] %# in place of IN

NSPredicate how to filter object fields

How do I filter an array of objects by a specific field?
My code:
NSMutableArray *inputArray = [[NSMutableArray alloc]init];
Person *person = [[Person alloc]init];
person.first_name = #"John";
[inputArray addObject: person];
person = [[Person alloc]init];
person.first_name = #"Jack";
[inputArray addObject: person];
NSString *expression = [NSString stringWithFormat:#"SUBQUERY(inputArray, $object, $object.first_name CONTAINS[c] J"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:expression];
NSMutableArray *filteredArray = [[inputArray filteredArrayUsingPredicate:predicate]mutableCopy];
NSLog(#"Count should be 2: %lu",(unsigned long)filteredArray.count);
This is the error I get:
'NSInvalidArgumentException', reason: 'Unable to parse the format string "SUBQUERY(inputArray, $object, $object.first_name CONTAINS[c] J"'
This is a basic example for testing. The real-case scenario is that I have an array of objects (Person or whatever) and I want to filter that array by certain fields within the objects ie first_name. As the user types we will filter a visual list based on what they type - so typing "J" would yield 2 results, but then when they type "Jo" only "John" appears on the list.
What am I doing wrong?
EDIT
Still doesn't seem to be working. Updated code:
DOVisitor *vi = [inputArray objectAtIndex:0];
NSLog(#"NAME: %#",vi.first_name);
NSPredicate *firstNamePredicate=[NSPredicate predicateWithFormat:#"first_name LIKE[cd] %#", #"Jo"];
NSPredicate *lastNamePredicate =[NSPredicate predicateWithFormat:#"last_name LIKE[cd] %#", #"Jo"];
NSPredicate *finalPredicate = [NSCompoundPredicate orPredicateWithSubpredicates : #[firstNamePredicate, lastNamePredicate]];
NSArray *filteredArray = [[inputArray filteredArrayUsingPredicate:finalPredicate]mutableCopy];
NSLog(#"Count should be 1: %d", [filteredArray count]);
I get an empty array back. However when I print the first object of the inputArray the console logs "John"
EDIT
Using CONTAINS instead of LIKE does the trick
You don't need a subquery for this, this is a very basic filter.
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"first_name CONTAINS[cd] %#", #"j"];
Let us say you have Person object and you are trying to search for both firstName and lastName, then you can use:
NSPredicate *firstNamePredicate=[NSPredicate predicateWithFormat:#"firstName LIKE[cd] %#", #"Jo"];
NSPredicate *lastNamePredicate =[NSPredicate predicateWithFormat:#"lastName LIKE[cd] %#", #"Jo"];
NSPredicate *finalPredicate = [NSCompoundPredicate orPredicateWithSubpredicates : #[firstNamePredicate, lastNamePredicate]];
The final Predicate is generated by oring the previous predicates. So even if Jo is present in firstName or lastName, that Person object will pass the predicate test.
Edit:
Get filtered objects with above predicate
NSArray *filteredArray = [inputArray filteredArrayUsingPredicate:finalPredicate];

How to create a predicate that compares all properties of an object?

For example, I have an object that has three properties: firstName, middleName, lastName.
If I want to search a string "john" in all the properties using NSPredicate.
Instead of creating a predicate like:
[NSPredicate predicateWithFormat:#"(firstName contains[cd] %#) OR (lastName contains[cd] %#) OR (middleName contains[cd] %#)", #"john", #"john", #"john"];
Can I do something like:
[NSPredicate predicateWithFormat:#"(all contains[cd] %#), #"john"];
"all contains" does not work in a predicate, and (as far as I know) there is no similar syntax to get the desired result.
The following code creates a "compound predicate" from all "String" attributes in the entity:
NSString *searchText = #"john";
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Entity" inManagedObjectContext:context];
NSMutableArray *subPredicates = [NSMutableArray array];
for (NSAttributeDescription *attr in [entity properties]) {
if ([attr isKindOfClass:[NSAttributeDescription class]]) {
if ([attr attributeType] == NSStringAttributeType) {
NSPredicate *tmp = [NSPredicate predicateWithFormat:#"%K CONTAINS[cd] %#", [attr name], searchText];
[subPredicates addObject:tmp];
}
}
}
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subPredicates];
NSLog(#"%#", predicate);
// firstName CONTAINS[cd] "john" OR lastName CONTAINS[cd] "john" OR middleName CONTAINS[cd] "john"
You can do it in such way like,
NSMutableArray *allTheContaint = [[NSMutableArray alloc] init];
[allTheContaint addObject:allTheContaint.firstName];
[allTheContaint addObject:allTheContaint.middleName];
[allTheContaint addObject:allTheContaint.lastName];
NSPredicate *predicateProduct = [NSPredicate predicateWithFormat:#"SELF CONTAINS[cd] %#", #"john"];
NSArray *filteredArray = [self.listOfProducts filteredArrayUsingPredicate:predicateProduct];
NSLog(#"%#", filteredArray);
But it is fix. :( not for dynamic :)

Resources