Filtering NSArray with NSPredicate - ios

Its my code :
-(NSArray *)searchTeamsWithPlayerPharse:(NSMutableArray *)teams phrase:(NSString *)phrase
{
NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:#"rel_Players.fullName CONTAINS[c] %#" ,phrase];
NSArray *searchResult = [teams filteredArrayUsingPredicate:searchPredicate];
return searchResult ;
}
It is not working. In array I have Team objects. Team has relationship with players and i want filtr with this relathionship and find only teams with players have pharse in fullName. How to change this NSPredicate

The ANY operator should work:
NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:#"ANY rel_Players.fullName CONTAINS[c] %#" ,phrase];
Some additional remarks:
a rel_ prefix is unusual and unnecessary: the plural form players is enough and the underscore can be omitted because the beginning of a new word is marked by an uppercase character (camel case).
The method does not need to take a mutable array argument. This restricts the use cases to arguments of type NSMutableArray. If you change the parameter type to NSArray * you can use instances of both NSArray and NSMutableArray.
The method does not work on the instance context: It does not have a single access to self. You can make a function out of it or – I would prefer that – make it a method of NSArray.
Taking this together:
#interface NSArray(TeamPlayerAddition)
-(NSArray *)teamsWithPlayerPharse:(NSString *)phrase
#end
#implementation NSArray(TeamPlayerAddition)
-(NSArray *)teamsWithPlayerPharse:(NSString *)phrase
{
NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:#"ANY rel_Players.fullName CONTAINS[c] %#" ,phrase];
return [self filteredArrayUsingPredicate:searchPredicate];
}
#end

Related

NSPredicate to compare identical string arrays?

Is it possible to use nspredicate to compare whether one NSArray is exactly equal to another NSArray of strings? I need this dome via predicates because of its possible I will add this predicate to a compound predicate.
The Array I am comparing against is a property of an NSDictionary.
So the answer was a mixture of both, I did use the predicatewithformat but got creative in the string inside, inspired by #akashivskyy and #avi
[predicatesArray addObject:[NSPredicate predicateWithFormat:#"ANY dynamic.values == %#", arr]];
Edit: As (partially) suggested by Avi, you may use the equality predicate:
NSArray *otherArray = #[ #"foo", #"bar" ];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self == %#", otherArray];
[predicate evaluateWithObject:#[ #"foo", #"bar" ]]; // YES
[predicate evaluateWithObject:#[ #"baz", #"qux" ]]; // NO
Alternatively, and if you have any trouble with format string in the future, you may always use a block predicate to perform your own logic:
NSArray *otherArray = #[ #"foo", #"bar" ];
NSPredicate *predicate = [NSPredicate predicateWithBlock:^(NSArray *evaluatedArray, NSDictionary<NSString *, id> *bindings) {
return [evaluatedArray isEqualToArray:otherArray];
}];
// use the predicate

use NSPredicate to filter object

Here say I have a array of objects with two attributes:
// array of object
NSArray *objects
// object
NSString *primaryTag;
NSArray *secondaryTag;
Since what I want is when the this object contains the givenTag, it could be passed to a new array called results;
Here is my codes:
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"primaryTag == %# || secondaryTag CONTAINS[c] %#", givenTag, givenTag];
results = [objects filteredArrayUsingPredicate:resultPredicate];
It seems that the primaryTag works well, but the secondaryTag doesn't work, can someone help me out. I am not that familiar with NSPredicate filtering. Thanks in advance.
The most efficient way to do that is with a NSCompoundPredicate like so:
NSArray *subPredicates = #[tag1, tag2, tag3];
NSPredicate *compoundPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:subPredicates];
Your question is a little unclear so you might also want:
andPredicateWithSubpredicates
Depending on exactly what the nature of the result set you are looking for.
See Apple Docs here: NSCompoundPredicate Docs
i implemented the following custom class:
#interface CustomObject : NSObject
#property (copy, nonatomic) NSString *primaryTag;
#property (strong, nonatomic) NSArray *secondaryTag;
#end
and overrode it's description method for the NSLog statement to print something we understand:
- (NSString *)description {
return [NSString stringWithFormat:#"primaryTag: %#, secondaryTag: %#", _primaryTag, [_secondaryTag componentsJoinedByString:#", "]];
}
then i created some objects from the custom class and added them to an array:
NSMutableArray *objects = [NSMutableArray array];
CustomObject *obj1 = [CustomObject new];
obj1.primaryTag = #"stringToSearchFor";
obj1.secondaryTag = #[#"notTheStringToSearchFor", #"somethingElse"];
[objects addObject:obj1];
CustomObject *obj2 = [CustomObject new];
obj2.primaryTag = #"differentString";
obj2.secondaryTag = #[#"nothingWeAreLookingFor"];
[objects addObject:obj2];
CustomObject *obj3 = [CustomObject new];
obj3.primaryTag = #"anotherOne";
obj3.secondaryTag = #[#"whoCaresForThisString", #"stringToSearchFor"];
[objects addObject:obj3];
finally i created a string to search for and the predicate:
NSString *givenTag = #"stringToSearchFor";
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"primaryTag == %# || secondaryTag CONTAINS[c] %#", givenTag, givenTag];
when i log out the result i get the correct results:
NSLog(#"%#", [objects filteredArrayUsingPredicate:resultPredicate]);
logs:
(
"primaryTag: stringToSearchFor, secondaryTag: notTheStringToSearchFor, somethingElse",
"primaryTag: anotherOne, secondaryTag: whoCaresForThisString, stringToSearchFor"
)
which is obj1 and obj3. correct! if it does not work for you there's gotta be something else wrong with your code...
If my understanding of the original question is incorrect, please let me know, and I will adjust my answer.
Problem: You have an array of objects with 2 properties. One is primaryTag, which is a string. The second is an array of secondaryTags, which is a collection of strings. You want to filter all objects where either the primaryTag matches, or where the search string matches one of the secondaryTags.
Answer The proper way to match strings is via MATCHES or CONTAINS.
NSPredicate *pPredicate =
[NSPredicate predicateWithFormat:#"%K CONTAINS[cd] %#",
#"primaryTag", searchString];
NSPredicate *sPredicate =
[NSPredicate
predicateWithFormat:#"SUBQUERY(%K, $st, $st CONTAINS[cd] %#).#count > 0",
#"secondaryTags", searchString];
NSCompoundPredicate *searchPredicate =
[NSCompoundPredicate orPredicateWithSubPredicates:#[ pPredicate, sPredicate ]];
How it works: The first predicate is a straightforward match. You can replace CONTAINS with MATCHES, if that better fits the kind of comparison you wish to make. The [cd] suffix means case-insensitive and diacritic-insensitive. It's normal to include those when searching/filtering, but again, it's up to you. Instead of embedding the property name in the predicate format string, I use %K and a replacement parameter. In production code, that replacement parameter would be a constant.
The second predicate is a little trickier. It uses a SUBQUERY() to filter the secondaryTags array, and returns the object as matching if at least one secondary tag matches the search string. SUBQUERY() is a function with 3 parameters. The first is the collection being searched. The second is a temporary variable that represents each item in the collection, in turn; it is used in the 3rd parameter. The 3rd parameter is a regular predicate. Each item in the collection that matches the filter is included in the output of SUBQUERY(). At the end, the matching secondary tags are counted (via #count), and if the count is greater than zero, the original object is considered to have matched, so will be included in the filtered output.
Finally, we combine these two predicates into one searchPredicate, which can now be used to filter your array of objects.
I seen this issue,
My normal approch is to use the NSPredicate twice,
So that I can track the result at every steps:
Option 1:
NSPredicate *resultPredicate1 = [NSPredicate predicateWithFormat:#"primaryTag == %#", givenTag];
results1 = [objects filteredArrayUsingPredicate:resultPredicate1];
NSPredicate *resultPredicate2 = [NSPredicate predicateWithFormat:#"secondaryTag CONTAINS[c] %#", givenTag];
finalResults = [results1 filteredArrayUsingPredicate:resultPredicate2];
Option 2:
Use NSCompoundPredicate to compound multiple filtering. You can easily find many examples on google and stackOverFlow.
Hope this will help,
Thanks

list of indexes in NSArray from NSPredicate

My question is very similar to : obj c -get list of indexes in NSArray from NSPredicate
But there is a difference. I have two NSArrays. The first is of names and the other is of phone numbers. I search into the "names" array to search for a name using the following code:
-(void)filterContentForSearchText:(NSString *)searchtext scope:(NSString *)scope {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#",searchtext];
self.searchResult = [ForMsgNamrarray filteredArrayUsingPredicate:predicate];
}
I am returned a filtered array which is fine. But based on the indexes of the filtered array I would also like to filter the array containing the phone numbers.
For example if I search "jh" I get "Jhone" in my search array. I also want to add the phone number of john in another array i.e "searchArrayPhNum"
Prepare a Model Object with following properties,
#interface Person : NSObject
#property (nonatomic,retain) NSString *name;
#property (nonatomic,retain) NSString *phoneNumber;
#end
and use single array ( an array of Person objects) instead of Two different arrays,
Your predicate would change like,
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.name beginswith[c] %#",searchtext];

How to find an object with a specific property which is in the array of an array, by using NSPredicate?

Suppose I have the following objects
class A {
NSArray *arrayOfB;
}
class B {
NSString *name;
}
Now, I have an array of As like below and each A contains 10 objects of B within its property arrayOfB.
NSArray *arrayOfAs; //contains objects of A
How can I get the objects of A depending upon specific match of name property of Bs inside of A, by using NSPredicate ?
I've tried googling, etc. and even writing various style of NSPredicate but did not succeed. Can anyone enlighten me how to do it?
This is what I tried so far:
NSPredicate *p = [NSPredicate predicateWithFormat:#"(SELF.name BEGINSWITH[c] %# IN SELF.arrayOfB)",myText];
NSArray *mySearchedArrayOfAs = [arrayOfAs filteredArrayUsingPredicate:p];
But I run into error which says "Unable to parse the predicate".
I think you need to use ANY operator, like this:
NSPredicate *p = [NSPredicate predicateWithFormat:#"ANY arrayOfB.name BEGINSWITH[c] %#", myText];

NSPredicate possibly matching multiple properties

I have a Car class with instance variables such as "color" and "make".
I need a NSPredicate that allows me to search for either color or make or both.
NSPredicate*predicate=[NSPredicate predicateWithFormat:#"(color contains[c] %#) AND (make contains[c] %#)", chosenColor,chosenMake];
This predicate requires that there is BOTH a color and a make. If the user only gives a color, no results will be returned because the make then will be "nil". No cars has nil for any instance variables.
Also, the search will be for many variables, not only color and make, so an if/case situation is not wanted. Is there any options that gives my the possibility to search for "AND if NOT nil". I will appreciate any help.
You can build your predicate format dynamically to test only non-nil attributes. More on that here. Also consider making your search diacritic-insensitive (adding a 'd' to your CONTAINS statement). Take "Škoda" for example. You want people to find it with "skoda" as well.
This is pretty easy with the NSCompoundPredicate API:
NSString *chosenColor = ...;
NSString *chosenMake = ...;
NSMutableArray *subpredicates = [NSMutableArray array];
if (chosenColor != nil) {
NSPredicate *p = [NSPredicate predicateWithFormat:#"color contains[cd] %#", chosenColor];
[subpredicates addObject:p];
}
if (chosenMake != nil) {
NSPredicate *p = [NSPredicate predicateWithFormat:#"make contains[cd] %#", chosenMake];
[subpredicates addObject:p];
}
NSPredicate *final = nil;
if ([subpredicates count] > 0) {
final = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
}

Resources