NSPredicate Crashes when trying to use CONTAINS - objective-c

The data structure that I want to question. Data is a Transformable field which in turn is a NSDictionary.
Obj = { //...
NSDictionary *data:#{
likesPeople:#[#{#"username":#"jack",#"id":#"ae3132"}]
}
}
what I want to do is search inside the NSArray *fetchResult to check that there is noone in likesPeople with X id .
My attempts on doing this always end up crashing highlighting that there is a problem in my NSPredicate declaration.
What am I doing wrong and How could I effectively fetch the information that I want?
SocialWall *theSocialWall = fetchResult[0];
NSLog(#"%#",theSocialWall.data);
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"data.likesPeople CONTAINS(c) %#",myUser.userWebID];
NSArray * result = [fetchResult filteredArrayUsingPredicate:predicate];
NSLog(#"%#",result);

not Contains(c) but Contains[c]
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
NSDictionary *d = #{#"key":#"hi my name dominik pich"};
NSArray *a = #[d];
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"key CONTAINS[c] %#",#"dominik"];
NSArray * result = [a filteredArrayUsingPredicate:predicate];
NSLog(#"%#",result);
}
}

Related

NSPredicate to match string with an array of prefixes

I'm unsure how to write this NSPredicate to achieve the following. I have an array of prefixes, and I want to know if any of them (plus an underscore) are the prefix of a given string. I don't need to know which matched, just a yes/no if any matched at all.
I can't seem to work this out, at the moment I have this
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
#autoreleasepool {
NSArray *bins = #[#"aaa", #"bbb", #"ccc"];
NSString* item = #"aaa_blah";
NSPredicate *pred = [NSPredicate predicateWithFormat:#"%# BEGINSWITH SELF", item];
NSLog(#"%#", [[bins filteredArrayUsingPredicate:pred] count] ? #"YES" : #"NO");
}
}
The only way I could think of doing it was filtering the array - so firstly is there a better approach?
And secondly, I want it to return true only if the prefix is followed by an underscore so
#[#"aaa", #"bbb", #"ccc"];
#"aaa_blah"; // YES
#"aaablah"; // NO
#"bbbblah"; // NO
I'm not sure how to do that?
+(void)checkIfExists:(NSArray *)prefixes inMyobjects:(NSArray *)myObjects withDivider:(NSString *)divider
{
divider = #"_";
prefixes = #[#"aaa",#"bbb",#"ccc"];
myObjects = #[#"aaa_sd",#"dsf_ds",#"aaa_sss",#"aaabbb"];
NSMutableArray * resultsOfPredicate = [NSMutableArray new];
for (NSString * pre in prefixes)
{
NSString * iAmLookingFor = [NSString stringWithFormat:#"%#%#", pre, divider];
NSPredicate *prefixPredicate = [NSPredicate predicateWithFormat:#"SELF beginsWith[c] %#", iAmLookingFor];
NSArray * resultOfSearch = [myObjects copy];
resultOfSearch = [resultOfSearch filteredArrayUsingPredicate:prefixPredicate];
NSLog(#"ros %#",resultOfSearch);
[resultsOfPredicate addObject:#([resultOfSearch count])];
}
for (int i = 0; i<[resultsOfPredicate count]; i++)
{
NSLog(#"prefix %# isAppeared:%d",[prefixes objectAtIndex:i], [[resultsOfPredicate objectAtIndex:i] boolValue]);
}
}
I hope this will help.

filter dictionary array by property that matches a different array

I have two arrays and I'm trying to filter the first (array1) with a matching property that exists in a second array (array2). The first array is a dictionary array with key 'name'. The second array is an array of objects with property 'name'. Is it possible to filter contents of 'array1' and display only those that have a matching 'name' found in 'array2'?
I've tried:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"name == #%",self.array2];
NSArray *results = [array1 filteredArrayUsingPredicate:pred];
NSLog(#"The results array is %#", results);
Rather than '==' I've tried a mix of 'IN' and '#K' and 'self' but it either crashes or results are 0.
NSPredicate *pred = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return [[array2 valueForKey:#"name"] containsObject:[evaluatedObject objectForKey:#"name"]];
}];
This should work with IN:
NSArray *matchSet = [self.array2 valueForKey:#"name"];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"name IN #%",matchSet];
Typed in Safari.
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html#//apple_ref/doc/uid/TP40001795-215891
Here's a quick example of how you could accomplish this:
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSArray *arrayOne = #[#{#"name": #"Alvin"}, #{#"name": #"Brian"}, #{#"name": #"Charlie"}];
BMPPerson *alvin = [[BMPPerson alloc] initWithName:#"Alvin"];
BMPPerson *charlie = [[BMPPerson alloc] initWithName:#"Charlie"];
NSArray *arrayTwo = #[alvin, charlie];
NSArray *values = [arrayTwo valueForKey:#"name"];
NSMutableArray *filteredValues = [NSMutableArray array];
[arrayOne enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString *name = [obj valueForKey:#"name"];
if ([values containsObject:name]) {
[filteredValues addObject:name];
}
}];
NSLog(#"%#", filteredValues);
}
return 0;
}
In the example, arrayOne is an NSArray of NSDictionary objects. Each object has a key of name.
The objects contained in arrayTwo are a basic NSObject subclass that has a name property.
To get the values of the name properties for all of the objects in arrayTwo we make use of the key-value coding method -valueForKey: which calls -valueForKey: on each object in the receiver and returns an array of the results.
We then create an NSMutableArray to hold the filtered results from arrayOne.
Next we enumerate the objects in arrayOne using the -enumerateObjectsUsingBlock: method. In this example, we know that the obj argument is an NSDictionary that has a key of name. Instead of casting to an NSDictionary and calling -objectForKey: we can simply call -valueForKey: and store the value in our local variable name. We then check to see if name is in the values array and if it is, add it to our filteredValues.

NSPredicate of multidimensional NSArray

Given is an NSArray with objects, each of which has an NSArray with floats, stored as NSNumbers.
I am trying to create an NSPredicate to filter my main array based on the float values. So, for instance, how to get all objects that have the value 234.6 +/- 0.8 as one of the floats in the sub-array?
I can do something like this for a one-dimensional NSArray of floats:
float targetFloat = 234.6;
float delta = 0.8;
filterPredicate = [NSPredicate predicateWithFormat: #"myFloat > %f AND myFloat < %f", (targetFloat - delta), (targetFloat + delta)];
filteredArray = [originalArray filteredArrayUsingPredicate: filterPredicate];
But how do I change it for my 2D NSArray with NSNumbers?
You can use "SELF[index]" in a predicate to access specific elements of the sub-array.
The following predicate finds all sub-arrays where the first element is in the
specified range:
float lowValue = 1.5;
float hiValue = 2.5;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF[0] > %f AND SELF[0] < %f", lowValue, hiValue];
NSArray *filtered = [array filteredArrayUsingPredicate:predicate];
If you want to find the sub-arrays that contain any number in the specified range, use
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY SELF BETWEEN %#", #[#(lowValue), #(hiValue)]];
Your predicate can access the object's property that holds the array by name; I've called this list in the example below. Then use the ANY keyword to check all the values in the array, and BETWEEN to find out if those values are within your chosen range.
#import <Foundation/Foundation.h>
#interface Grumolo : NSObject
#property (copy, nonatomic) NSArray * list;
#end
#implementation Grumolo
- (NSString *)description
{
return [NSString stringWithFormat:#"%#: %p, list: %#", NSStringFromClass([self class]), self, [self list]];
}
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
float target = 234;
float delta = 0.8;
NSPredicate * p = [NSPredicate predicateWithFormat:#"ANY list BETWEEN %#", #[#(target-delta), #(target+delta)]];
NSArray * yes = #[#234, #10, #100];
NSArray * yes2 = #[#0, #16, #234];
NSArray * no = #[#1, #2, #3];
Grumolo * g1 = [Grumolo new];
[g1 setList:yes];
Grumolo * g2 = [Grumolo new];
[g2 setList:yes2];
Grumolo * g3 = [Grumolo new];
[g3 setList:no];
NSLog(#"%#", [#[g1, g2, g3] filteredArrayUsingPredicate:p]);
}
return 0;
}
You might also like to try predicateWithBlock:, which would let you express what you're trying to do with a traditional loop over each array, returning YES if you find an element that meets your criteria and NO if you exhaust the list.
NSPredicate * pb = [NSPredicate predicateWithBlock:^BOOL(Grumolo * evaluatedObject, NSDictionary *bindings) {
NSArray * list = [evaluatedObject list];
__block BOOL result = NO;
[list enumerateObjectsUsingBlock:^(NSNumber * obj, NSUInteger idx, BOOL *stop) {
BOOL moreThanLower = (NSOrderedDescending == [obj compare:#(target-delta)]);
BOOL lessThanUpper = (NSOrderedAscending == [obj compare:#(target+delta)]);
if( moreThanLower && lessThanUpper ){
*stop = YES;
result = YES;
return;
}
}];
return result;
}];

How to modify this predicate so it handles multiple keywords efficiently

I have this predicate:
NSPredicate * thePredicateKeyword = [NSPredicate predicateWithFormat:#"any keywords.thekeyword beginswith [cd] %#", searchTerm];
Basically each business have many to many relationship with keywords.
But suppose I do not have one searchTerm. Say I have an array.
How would I do so?
I suppose I can just make predicate for each and combine them with or predicate, etc.
However, is there a way to more efficiently do this using in keywords or stuff like that?
What about a function that returns something like this:
-(NSPredicate *)createCompoundPredicateForSearchTerms:(NSArray *)searchTerms
{
NSMutableArray *subPredicates = [[NSMutableArray alloc] init];
NSEnumerator *searchTermEnum = [searchTerms objectEnumerator];
NSString *searchTerm;
while (searchTerm = [searchTermEnum nextObject]) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"keywords.thekeyword beginswith [cd] %#", searchTerm];
[subPredicates addObject:predicate];
}
return [NSCompoundPredicate andPredicateWithSubpredicates:subPredicates];
}
This is what I actually use. However, the anwer I chose is what inspire it.
NSArray * keywords = [searchTerm componentsSeparatedByString:#" "];
NSMutableArray * keywordPredicates = [NSMutableArray array];
for (NSString * aKeyword in keywords) {
NSPredicate * thePredicateKeyword = [NSPredicate predicateWithFormat:#"any keywords.thekeyword beginswith [cd] %#", aKeyword];
[keywordPredicates addObject:thePredicateKeyword];
}
NSPredicate * thePredicateKeyword = [NSCompoundPredicate orPredicateWithSubpredicates:keywordPredicates];
return thePredicateKeyword;

what is the use of stringsByAppendingPaths

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSArray *array = [[NSArray alloc] initWithObjects:#"/tmp/1.txt" ,#"/tmp/2.txt", nil];
NSLog(#"%#", array);
NSString *result = [[NSString alloc] init];
NSArray *array2 = [[NSArray alloc]initWithArray:[result stringsByAppendingPaths:array]];
NSLog(#"%#", array2);
}
return 0;
}
The argument we provide to stringsByAppendingPaths: is an array and so is the return type. So what is the use of this NSString method?
Well, you're appending empty string (result), so it doesn't make much sense. But if your receiver contains say /tmp and the array contains 1.txt and 2.txt, getting the array /tmp/1.txt and /tmp/2.txt makes sense.