Obj-C - NSPredicate - Can I implement an 'or IF' statement? - ios

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

Related

IOS/Objective-C: Out of Range Error with NSPredicate

I have built an NSPredicate similar to that below before and it worked perfectly. However, this time, it is generating the error:
'NSRangeException', reason: '-[NSTaggedPointerString characterAtIndex:]: Index 1 out of bounds; string length 1'
Here is how I build the predicate:
NSString *shortTitleClause = nil;
NSString *longTitleClause = nil;
Edit:
Adding clauses:
shortTitleClause =[NSString stringWithFormat:#"(shorttitle contains[c] %#)", searchText];
longTitleClause =[NSString stringWithFormat:#"(longtitle contains[c] %#)", searchText];
//My actual predicate has many more clauses but am getting same error no matter how many.
NSMutableArray *predArr = [#[] mutableCopy];
if (shortTitleClause.length > 0){
[predArr addObject:shortTitleClause];
}
if (longTitleClause.length > 0){
[predArr addObject:longTitleClause];
}
NSString *predStr = [predArr componentsJoinedByString:#"||"];
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:predStr];
searchResults = [theBooks filteredArrayUsingPredicate:resultPredicate];
When searching for the letter 'S' the predicate logs as: `(shorttitle contains[c] S)||(longtitle contains[c] S)`
It is not clear to me what the taggedPointerString refers to me. Can anyone see why I am getting this error?
You cannot use stringWithFormat to replace %# values when preparing predicates. Use predicateWithFormat instead. And don't join them using componentsJoinedByString - use NSCompoundPredicate to combine multiple predicates:
shortTitlePredicate = [NSPredicate predicateWithFormat:#"(shorttitle contains[c] %#)", searchText];
longTitlePredicate = [NSPredicate predicateWithFormat:#"(longtitle contains[c] %#)", searchText];
NSPredicate *resultPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:#[shortTitlePredicate,longTitlePredicate]];

How to concatenate two fields for search with NSPredicate?

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

how to work with NSPredicate

I am try to search word which contain "EVBAR02". Can any body help me in this case. Here is Array Directory.
Here is code.
`NSMutableArray *filteredListContent = [NSMutableArray arrayWithArray:arrayGallery];
NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"imageUrl CONTAINS[cd] EVBAR02"];
[filteredListContent filterUsingPredicate:predicate];`
arrayGallery = (
{
imageId = "04";
imageUrl = "/article/THEV-EVBAR04.jpg";
},
{
imageId = "02";
imageUrl = "/article/THEV-EVBAR02.jpg";
},
{
imageId = "06";
imageUrl = "/article/THEV-EVBAR06.jpg";
}
)
But Its not working. What to do?
The ...WithFormat part of predicateWithFormat: works the same way like stringWithFormat:
NSString *searchString = #"EVBAR02";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"imageUrl CONTAINS[cd] %#", searchString];
Or literally in single quotes:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"imageUrl CONTAINS[cd] 'EVBAR02'"];
The quotation is required as described in the documentation:
String constants must be quoted within the expression—single and
double quotes are both acceptable, but must be paired appropriately
(that is, a double quote (") does not match a single quote ('))
Vadian is right.
And if you want to pass the field name as a parameter, use %Kin place of %#:
NSString *searchField = #"imageUrl";
NSString *searchString = #"EVBAR02";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K CONTAINS[cd] %#", searchField, searchString];
You have to set single quotes in your search string :
NSPredicate *predicate = [NSPredicate predicateWithFormat : #"imageUrl CONTAINS[cd] 'EVBAR02' "]
NSString *myString = #"EVBAR02";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"imageUrl
contains[cd] %#", myString];
NSMutableArray *arrResult =[filteredListContent filteredArrayUsingPredicate:predicate];
There is no need of NSString stringWithFormat, directly use NSPredicate predicateWithFormat as below:
NSMutableArray *filteredListContent = [NSMutableArray arrayWithArray:arrayGallery];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"imageUrl CONTAINS[cd] 'EVBAR02'"];
[filteredListContent filterUsingPredicate:predicate];
Hope it will help:)

How to use a compound NSPredicate?

I would like to know how if at all to use a compound NSPredicate?
I have made an attempt as follows however the currentInstall array is exactly the same at the start as it is after the predicate has been applied.
NSArray *currentInstall = [coreDataController filterReadInstalls:selectedInstallID];
NSArray *tempArray = [currentInstalls filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"cHR == 0"]];
currentInstalls = [tempArray copy];
NSPredicate *predicateAreaString = [NSPredicate predicateWithFormat:#"area == %#", [myFilter objectForKey:#"area"]];
NSPredicate *predicateBString = [NSPredicate predicateWithFormat:#"stage == %#", [myFilter objectForKey:#"area2"]];
NSPredicate *predicateCString = [NSPredicate predicateWithFormat:#"partCode == %#", [myFilter objectForKey:#"area3"]];
NSPredicate *predicateDString = [NSPredicate predicateWithFormat:#"doorNo CONTAINS[cd] %#", [myFilter objectForKey:#"door"]];
NSPredicate *predicateEString = [NSPredicate predicateWithFormat:#"doorDesc CONTAINS[cd] %#", [myFilter objectForKey:#"doorDesc"]];
NSPredicate *compoundPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:#[predicateAreaString, predicateBString, predicateCString, predicateDString, predicateEString]];
NSMutableArray *filteredArray = [NSMutableArray arrayWithArray:[currentInstalls filteredArrayUsingPredicate:compoundPredicate]];
currentInstalls = [filteredArray mutableCopy];
There doesn't seem to be anything obviously wrong with the way you have implemented NSCompundPredicate. If you are not trying to And or Not predicates then I would say it is something wrong with your predicate formats and how they match the array you are filtering.
I would try to use just 2 of the predicates to create an NSCompundPredicate then get that working or see what is causing your issue. NSHipster also has some good info about NSPredicates.

NSPredicate search LIKE

i'm trying to filter a string array with this predicate:
[NSPredicate predicateWithFormat:#"SELF LIKE[c] '#*!%d'", aNumber]
Every string which is like #WILDCARD!ANY_NUMBER is valid.
But it doesn't work :(
Can you help me?
EDIT:
NSString *pattern = [#"#*!" stringByAppendingFormat:#"%d", numberVariable];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", pattern];
NSArray *filteredArray = [anArray filteredArrayUsingPredicate:pred];
The array anArray contains Strings like #0!-1 (numberVariable is -1) but the array filterdArray is empty. So the regex doesn't work.
EDIT:
My Solution:
NSString *pattern = [#"#.*!\\" stringByAppendingFormat:#"%d", numberVariable];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", pattern];
NSArray *filteredArray = [anArray filteredArrayUsingPredicate:pred];
To find all strings that look like "#ANY_CHARACTERS!ANY_NUMBER" with an arbitrary number, you need the "MATCHES" operator with a regular expression:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", #"#.*!\\d+"];
NSArray *filtered = [yourArray filteredArrayUsingPredicate:pred];
If you have a specific number aNumber and want to find all strings of the form
"#ANY_CHARACTERS!<aNumber>", then the following should work:
NSString *pattern = [#"#*!" stringByAppendingFormat:#"%d", aNumber];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"SELF LIKE %#", pattern];
NSArray *filtered = [yourArray filteredArrayUsingPredicate:pred];
The problem with your
[NSPredicate predicateWithFormat:#"SELF LIKE[c] '#*!%d'", aNumber]
is that %d inside quotation marks is not replaced by aNumber.

Resources