NSCompoundPredicate not filtering array - ios

To test out a restaurant searching app I included 4 test restaurants in a JSON file which populate a table view correctly with their corresponding properties. In 3 text fields I filter the array with a name, average entree price and rating, yet when I pass it to the method the filtered array logged is not filtered. I don't see anything wrong with my predicate code though, any ideas? Thank you!
- (void)searchRestaurantsWithName:(NSString *)name price:(int)price andRating:(int)rating completion:(void (^)(NSArray *restaurants))completion {
NSMutableArray *restaurantsToFilter = [[RestaurantController sharedInstance].restaurants mutableCopy];
NSPredicate *namePredicate = [NSPredicate predicateWithFormat:#"name CONTAINS[c] %#", name];
NSPredicate *pricePredicate = [NSPredicate predicateWithFormat:#"price < %i", price];
NSPredicate *ratingPredicate = [NSPredicate predicateWithFormat:#"rating > %i", rating];
NSPredicate *compoundPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:#[namePredicate, pricePredicate, ratingPredicate]];
NSArray *filteredArray = [restaurantsToFilter filteredArrayUsingPredicate:compoundPredicate];
completion(filteredArray);
}
The method the button calls
- (void)filterArray {
[self searchRestaurantsWithName:self.nameTextField.text price:[self.priceTextField.text intValue] andRating:[self.ratingTextField.text intValue] completion:^(NSArray *restaurants) {
[self.tableView reloadData];
NSLog(#"%#", restaurants);
}];
}

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 predicate to find if string value exists

I have a NSMutableArray of objects with tag attributes assigned to them. I am trying to find if any of these objects have a tag assigned to them of the string value "a".
my code so far:
for (Object *object in self.array)
{
NSDictionary *attrs = [object propertyValue:#"attrs"];
NSString *tag = attrs[#"tag"];
}
Can I do something like:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"a"];
NSArray *results = [self.array filteredArrayUsingPredicate:predicate];
not sure how it works?
Try this
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"tag == %#", #"a"];
NSArray *result = [NSMutableArray arrayWithArray:[self.array filteredArrayUsingPredicate:predicate]];
Use 'contains[c]' instead of '==' if you want to perform case-insensitive search.
If you want to filter for any other property, replace 'tag' with that property name.
You will need to do something more like :
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.property_name contains[c] '%#'", #"a"];
NSArray *result = [NSMutableArray arrayWithArray:[self.array filteredArrayUsingPredicate:predicate]];

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];

NSPredicate to arrange NSMutableArray Objects?

I have multiple category list(around 45). i want to show some of the category to first like (Helicopter,Lake Monster,Dinosaur Attack) that will come at the starting after this remaning other will come. i have used the following code.
That works fine. But its to lengthy. so i want to filter this code.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF IN %#", #[#"Helicopter", #"Lake Monster",#"Dinosaur Attack"]];
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:#"packageName CONTAINS[cd] %#", #"Helicopter"];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:#"packageName CONTAINS[cd] %#", #"Lake Monster"];
NSPredicate *predicate3 = [NSPredicate predicateWithFormat:#"packageName CONTAINS[cd] %#", #"Dinosaur Attack"];
NSMutableArray *filteredArray = [[NSMutableArray alloc]init];
NSArray *arr1=[packages filteredArrayUsingPredicate:predicate1];
NSArray *arr2=[packages filteredArrayUsingPredicate:predicate2];
NSArray *arr3=[packages filteredArrayUsingPredicate:predicate3];
[filteredArray insertObject:[arr1 objectAtIndex:0] atIndex:0];
[filteredArray insertObject:[arr2 objectAtIndex:0] atIndex:1];
[filteredArray insertObject:[arr3 objectAtIndex:0] atIndex:2];
[packages removeObject:[arr1 objectAtIndex:0]];
[packages removeObject:[arr2 objectAtIndex:0]];
[packages removeObject:[arr3 objectAtIndex:0]];
So is there any way to achieve this result with shortest method?
Just cleaning up your own code, you could do the following:
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:#"packageName CONTAINS[cd] %#", #"Helicopter"];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:#"packageName CONTAINS[cd] %#", #"Lake Monster"];
NSPredicate *predicate3 = [NSPredicate predicateWithFormat:#"packageName CONTAINS[cd] %#", #"Dinosaur Attack"];
NSMutableArray *filteredArray = [[NSMutableArray alloc]init];
for (NSPredicate *predicate in #[predicate1, predicate2, predicate3]) {
NSArray *arr=[packages filteredArrayUsingPredicate:predicate];
[filteredArray addObject:arr[0]];
[packages removeObject:arr[0]];
}
You should probably create a class (lets call it STOElement) that has two properties, (NSString*)text, and (NSNumber*)order. Create an instance of that class for each element 'Helicopter' etc, set that as the text, and then set the order you would like that element to appear in as the order (1,2,3 etc).
Then use the sortedArrayUsingComparator: to get an array with the order you want
NSArray* sortedArray = [arrayOfElements sortedArrayUsingComparator:^NSComparisonResult(STOElement* element1, STOElement* element2) {
return [element1.order compare:element2.order];
}];

Filter array by first letter of string property

I have an NSArray with objects that have a name property.
I would like filter the array by name
NSString *alphabet = [agencyIndex objectAtIndex:indexPath.section];
//---get all states beginning with the letter---
NSPredicate *predicate =
[NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alphabet];
NSMutableArray *listSimpl = [[NSMutableArray alloc] init];
for (int i=0; i<[[Database sharedDatabase].agents count]; i++) {
Town *_town = [[Database sharedDatabase].agents objectAtIndex:i];
[listSimpl addObject:_town];
}
NSArray *states = [listSimpl filteredArrayUsingPredicate:predicate];
But I get an error - "Can't do a substring operation with something that isn't a string (lhs = <1, Arrow> rhs = A)"
How can I do this? I would like to filter the array for the first letter in name being 'A'.
Try with following code
NSPredicate *pred = [NSPredicate predicateWithFormat:#"SELF like %#", yourName];
NSArray *filteredArr = [yourArray filteredArrayUsingPredicate:pred];
EDITED :
NSPredicate pattern should be:
NSPredicate *pred =[NSPredicate predicateWithFormat:#"name beginswith[c] %#", alphabet];
Here is one of the basic use of NSPredicate for filtering array .
NSMutableArray *array =
[NSMutableArray arrayWithObjects:#"Nick", #"Ben", #"Adam", #"Melissa", #"arbind", nil];
NSPredicate *sPredicate = [NSPredicate predicateWithFormat:#"SELF contains[c] 'b'"];
NSArray *beginWithB = [array filteredArrayUsingPredicate:sPredicate];
NSLog(#"beginwithB = %#",beginWithB);
NSArray offers another selector for sorting arrays:
NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(Person *first, Person *second) {
return [first.name compare:second.name];
}];
If you want to filter array take a look on this code:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == %#", #"qwe"];
NSArray *result = [self.categoryItems filteredArrayUsingPredicate:predicate];
But if you want to sort array take a look on the following functions:
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context;
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context hint:(NSData *)hint;
- (NSArray *)sortedArrayUsingSelector:(SEL)comparator;
visit https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Collections/Articles/Arrays.html
use this
[listArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
Checkout this library
https://github.com/BadChoice/Collection
It comes with lots of easy array functions to never write a loop again
So you can just do
NSArray* result = [thArray filter:^BOOL(NSString *text) {
return [[name substr:0] isEqualToString:#"A"];
}] sort];
This gets only the texts that start with A sorted alphabetically
If you are doing it with objects:
NSArray* result = [thArray filter:^BOOL(AnObject *object) {
return [[object.name substr:0] isEqualToString:#"A"];
}] sort:#"name"];

Resources