Objective C Predicate of an array using a range of numbers - objective-c

So I have an nspredicate that I am using to filter values in a json array. Instead of just searching for one value, I would like the predicate to find objects that are within a range of numbers such as 0-1.0 or 1.1-2.0.
This is my current predicate:
NSPredicate *Predicate = [NSPredicate predicateWithFormat:#"Engine CONTAINS %#", #"?"];
It is probably a simple solution but I have yet to find an answer to this. Thank you for your time.

Please read documentation: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSPredicate_Class/Reference/NSPredicate.html
You can use conditions like AND and OR as well as inequality operations < and >

There are plenty of ways to do this and the docs have a few examples - see the Basic Comparisons section.
A basic solution would probably look like this
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"Engine BETWEEN %#", #[ #0, #1]];

Related

Fastest Way to Filter on Multiple Predicates in Obj-C

I am doing a lengthy filter quite often and would like to know if there is any difference in performance between the following methods, or if they are just a matter of style?
NSPredicate *predicate = [NSPredicate predicateWithFormat:#""];
NSPredicate *blockPredicate = [NSPredicate predicateWithBlock:nil];
NSCompoundPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:#[]];
I did find another post mentioning they were a matter of style, but it did not discuss predicateWithBlock or go into any detail of how these methods work.
I have another question that is semi-related: is it faster to in-line the predicates passed into an NSCompoundPredicate, or is it the same speed as declaring them outside as variables and passing the variables in? i.e.
NSCompoundPredicate *cp = [NSCompoundPredicate andPredicateWithSubpredicates:
#[[NSPredicate predicateWithFormat:""], [NSPredicate predicateWithFormat:""]];
or
NSCompoundPredicate *cp = [NSCompoundPredicate andPredicateWithSubpredicates:
#[pred1, pred2]];
Any explanation on this would be greatly appreciated, thank you

NSPredicate to get a single attribute back from multiple objects in an array

This seems like it would be fairly simple to do, but I can't find anything referencing this specifically.
Say I have an array of Post objects that each have an objectId. How can I create an array of only the objectId's?
something like:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"objectId ALL"]; // I just want all the objectIds...
NSArray *results = [[self.objects filteredArrayUsingPredicate:predicate] mutableCopy];
or
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"objectId matches {anything}"];
NSPredicate cannot return anything other than BOOL, so it cannot return objectId. Moreover, filteredArrayUsingPredicate: can change the number of items in your array, but it will keep the objects themselves unchanged.
If you want to start with one object and produce another object, you need NSExpression. It can transform your object into something else - for example, by projecting one of its attributes. However, Cocoa offers no built-in way of applying NSExpression to an NSArray in a way similar to filteredArrayUsingPredicate:, so NSExpression would not help here.
You can solve this by using a little trick, though:
NSString *key = NSStringFromSelector(#selector(objectId));
NSMutableArray *allIds= [[array valueForKey:key] mutableCopy];
If you use this in production code, it is a good idea to document it heavily by a few lines of comments. Otherwise, the readers of your code (including you in about six months or so) are virtually guaranteed to get confused.
Ok so it turns out this is not a task for NSPredicate, which is why I couldn't find out how to do it using that. Instead I can do this pretty easily with key-value coding (KVC).
If you want to simply retrieve something and not filter then:
NSArray *results = [self.objects valueForKey:#"objectId"];

Using NSPredicate to search NSArray attribute of core data entity

I've searched far and wide to find a solution to this problem. All of my attempts result in 0 results. Here is the general data structures:
Core Data Entity A {
stringAttribute string
....
transformableAttribute(NSArray of NSString objects) keywords
}
where keywords = [NSArray arrayWithObjects:#"string 1",#"string 2",#"string 3",nil]
I'm trying to run a predicate to search the NSArray transformable attribute.
I've tried the following against entity A. The core data store is a sqlite store.
NSString *term = #"string 1";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY keywords like[cd] %#", term];
----> Results in 0 matches
NSArray *termArray = [NSArray arrayWithObject:#"string 1"];
NSPredicate *predicate = [NSPredicate predicateWithFormat#"ANY keywords in %#", termArray];
----> Results in 0 matches
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(keywords, $x, $x like %#).#count > 0", term]
----> Results in an error that a non-relationship cannot be a subquery collection
I've tried some permutations of the above, but still no results. Any advice? Is this possible with Core data?
Thanks!
I'm not use with transformableAttribute that is an element of Core Data that I haven't got into, but if I recall you can't predicate on them. (so If I'm wrong please some one call me on this)
But when I see that your transformableAttribute is an array of string I just want to say why do you want an array in a database?
Why not make a relationship? A one to many relationship if your array can have different number of string.
Core Data is an abstraction of a Data Base, in a DB you don't use array, you use tables. That would probably simplify your life and make the fetching possible.

need help on a simple predicate to match any word in a string to a property

Let's say i want to let user search for my objects using a name property of the objects.
I have no problem if the user only enters one word:
e.g: facial
My predicate will be:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name CONTAINS[cd] %#", word];
But what if user enter more than one word separated by space?
I want to do sth like:
NSArray *words = [query componentsSeparatedByString:#" "];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name CONTAINS[cd] ANY %#", words];
But it doesnt work. Any guidance?
Thanks!
Another way of doing this (and I just learnt this myself as a result of your question) is to use subqueries. Check this SO question for more details. You can use subqueries in the following manner –
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SUBQUERY(%#, $str, SELF CONTAINS[cd] $str).#count != 0", words];
NSLog(#"%#", [array filteredArrayUsingPredicate:predicate]);
This seems to work as I've tested it myself but this could also be the arcane & obscure way that Dave has mentioned as it finds no mention in the Predicate Programming Guide.
The format for a SUBQUERY can be found here. It's the same link that you will find in the question linked earlier.
As you mentioned (correctly) in the comment, you can do this by building a compound predicate predicate, although you'll want to use orPredicateWithSubpredicates, and not the and variant.
That really is the best way to do this. There are others, but they rely on more arcane and obscure uses of NSPredicate, and I really recommend going with the build-a-compound-predicate route.

NSPredicate case-insensitive matching on to-many relationship

I am implementing a search field where the user can type in a string to filter the items displayed in a view. Each object being displayed has a keywords to-many relationship, and I would like to be able to filter the objects based on their keywords. Each keyword object has a name property, so I've set up an NSPredicate to do the filtering that looks like this:
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"keywords.name CONTAINS %#", self.searchString];
This works, but the problem is that the search is case-sensitive, so if the keyword has a capital letter but the user types in all lowercase, no matches are found. I've tried the following modification:
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"keywords.name CONTAINS[c] %#", self.searchString];
But that doesn't make any difference in the case sensitivity of the matching. Is there a way to do this case-insensitive matching using just a plain predicate? Or will I need to implement some sort of custom accessor on the keyword class, e.g. write a lowercaseName method and match against a lowercased version of the search string instead?
Addendum:
After further exploration, the workaround of adding a custom accessor works OK for manual use of NSPredicate, but does not work at all when using NSFetchRequest with Core Data, which only works when querying attributes defined in the Core Data model.
If I understand you correctly, you want your predicate to be true whenever any keywords name matches the search string. For this you need to test with the ANY keyword like this:
[NSPredicate predicateWithFormat:#"ANY keywords.name CONTAINS[c] %#", ...];
This will search the keywords and return true if any of those keywords name contains your search string.
I believe the answer is:
[NSPredicate predicateWithFormat:#"keywords.name CONTAINS[cd] %#", self.searchString];
String comparisons are by default case and diacritic sensitive. You can modify an operator using the key characters c and d within square braces to specify case and diacritic insensitivity respectively, for example firstName BEGINSWITH[cd] $FIRST_NAME.
Predicate Format String Syntax
If you is trying to catch only the equals names but with insensitive case, I think it is the best solution
[NSPredicate predicateWithFormat:#"ANY keywords.name LIKE[c] %#", ...];
You helped me a lot. Thanks guys!!!
In my case I did:
[NSPredicate predicateWithFormat:#"ANY name LIKE[c] %#", #"teste"];
If you must match the keyword but the search must be case-insensitive then you should use NSPredicate(format: "keywords.name =[c] %#", self.searchString)
LIKE does not work on string literals.
If you want both case insensitive and wildcard, use this:
NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"(name like[c] '*%#*')",#"search"]];