I have an array of search values that I would like to use in conjunction with a LIKE query in an NSPredicate:
NSPredicate *p = [NSPredicate predicateWithFormat:#"textField IN LIKE[c] %#", array];
This doesn't work, but is this possible to see if textfield has any LIKE comparisons to each value in the array?
You should use NSCompoundPredicate. It let's you combine a series of LIKE predicates with OR.
NSMutableArray *subpredicates = [NSMutableArray array];
for(NSString *text in array)
[subpredicates addObject:[NSPredicate predicateWithFormat:#"textfield LIKE %#",text]];
NSPredicate *finished = [NSCompoundPredicate orPredicateWithSubpredicates:subpreds];//Your final predicate
Related
Right now I have an array that has around 100000 elements. I've created a search bar for it but I think due to the number of elements that it is parsing through my phone lags when using the search bar. Is there a way to fix this?
Have you tried using NSPredicate?
NSMutableArray *array = [NSMutableArray arrayWithObjects:#"Nick", #"Ben", #"Adam", #"Melissa", nil];
NSPredicate *bPredicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] 'a'"];
NSArray *beginWithA = [array filteredArrayUsingPredicate:bPredicate];
// beginWithA contains { #"Adam" }.
NSPredicate *sPredicate = [NSPredicate predicateWithFormat:#"SELF contains[c] 'e'"];
[array filterUsingPredicate:sPredicate];
// array now contains { #"Nick", #"Ben", #"Melissa" }
That being said, with 100000 elements, wouldn't a persistent store make more sense?
I am trying to limit array of objects getting with [NSArray filteredArrayUsingPredicate] for better performance.
My Code:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.Name contains[c] %#", searchText];
NSArray *filteredArray = [self.dataArray filteredArrayUsingPredicate:predicate];
My dataArray contains about 30.000 objects and I want to limit result array 50. (I need some break statement after 50 match found.) How can I achieve this?
Use simple for-in loop, NSMutableArray builder and -[NSPredicate evaluateWithObject:] method.
NSMutableArray *builder = [NSMutableArray arrayWithCapacity:50];
for (id object in array) {
if ([predicate evaluateWithObject:object]) {
[builder addObject:object];
if (builder.count >= 50) break;
}
}
I noticed you tagged the question by Core Data. If you can use NSFetchRequest, then just set its fetchLimit to 50.
How about this?
myArray = [originalArray filteredArrayUsingPredicate:myPredicate];
if ([myArray count] > resultLimit) {
myArray = [myArray subarrayWithRange:NSMakeRange(0, resultLimit)];
}
How can I use NSPredicate to filter the values from array ivar against search query ? I manage to use NSPredicate against string ivar. I have one user defined class named as "User" which is used to create User from AddressBook. Here is my code
// User Defined Class named as "User"
// In User.h
#interface User : NSObject {
NSString *firstName;
NSString *lastName;
NSString *company;
UIImage *userImage;
NSArray *phoneNumberArray;
NSArray *emailArray;
NSArray *urlArray;
NSArray *addressArray;
NSString *notes;
NSString *dateOfBirth;
}
// In SearchViewController.m
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
// contactsArray is NSMutableArray
contactsArray = [Search searchContactsWithQuery:searchText];
NSLog(#"contactsArray count => %d",[contactsArray count]);
[contactsTableView reloadData];
}
// In Search.m
+(NSMutableArray*)searchContactsWithQuery:(NSString*)query {
NSLog(#"Query => %#",query);
NSMutableArray* predicates=[[NSMutableArray alloc] init];
// Create all predicates
NSPredicate * firstNamePredicate = [NSPredicate predicateWithFormat:#"firstName contains %#",query];
[predicates addObject:firstNamePredicate];
NSPredicate * lastNamePredicate = [NSPredicate predicateWithFormat:#"lastName contains %#",query];
[predicates addObject:lastNamePredicate];
NSPredicate * companyPredicate = [NSPredicate predicateWithFormat:#"company contains %#",query];
[predicates addObject:companyPredicate];
// Don't know how to use on array
// === START of ARRAY Predicate ====
NSPredicate *phoneNoPredicate = [NSPredicate predicateWithFormat:#"phoneNumberArray IN %#",query];
[predicates addObject:phoneNoPredicate];
NSPredicate *emailPredicate = [NSPredicate predicateWithFormat:#"emailArray contains %#",query];
[predicates addObject:emailPredicate];
NSPredicate *urlPredicate = [NSPredicate predicateWithFormat:#"urlArray contains %#",query];
[predicates addObject:urlPredicate];
NSPredicate *addressPredicate = [NSPredicate predicateWithFormat:#"addressArray contains %#",query];
// === END of ARRAY Predicate ====
NSPredicate *notesPredicate = [NSPredicate predicateWithFormat:#"notes contains %#",query];
[predicates addObject:notesPredicate];
NSPredicate *dobPredicate = [NSPredicate predicateWithFormat:#"dateOfBirth contains %#",query];
[predicates addObject:dobPredicate];
// Add predicates to array
NSPredicate *compoundPredicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicates];
NSArray * filteredArray = [APP_DELEGATE.allUsersArray filteredArrayUsingPredicate:compoundPredicate];
return [NSMutableArray arrayWithArray:filteredArray];
}
phoneNumberArray,emailArray,urlArray & addressArray are used because user may have multiple entries for phone no , email, address , url like HOME , WORK, iPhone, Other etc.
How can I use predicates on array? Any kind of help is appreciated. Thanks
You are doing the correct way, but you need to create your Predicates with String values instead of passing the Objects directly.
You need to use %k instead of %# like
[NSPredicate predicateWithFormat:#"firstName contains %k",query];
Please let me know if this helps.
Is it possible to use aggregate operator such as #min inside a predicate?
BTW The predicate filters an array of objects.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"ANY SELF.score == #min.score"];
I know you can retrieve the min value using the key-value operators eg:
NSNumber *minScore = [myArray valueForKeyPath:#"#min.score"];
So far I only get errors about the objects not being key value compliant for "#min".
Thanks
The reason that you're getting that error is that the predicate is being applied to each object in myArray, and those objects apparently don't support the key path #min.score. NSPredicate does have support for at least some of the collection operators, though. Here's a simple example that works:
NSDictionary *d1 = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:35] forKey:#"score"];
NSDictionary *d2 = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:52] forKey:#"score"];
NSDictionary *d3 = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:13] forKey:#"score"];
NSDictionary *d4 = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:19] forKey:#"score"];
NSArray *array = [NSArray arrayWithObjects:d1, d2, d3, d4, nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.score == %#.#min.score", array];
NSLog(#"Min dictionaries: %#", [array filteredArrayUsingPredicate:predicate]);
You can see that in this case, the #min.score key path is applied to the array, which makes sense. The output is an array containing the one dictionary that contains the minimum value:
Min dictionaries: (
{
score = 13;
}
)
I have an NSArray of objects, which has a particular property called name (type NSString).
I have a second NSArray of NSStrings which are names.
I'd like to get an NSArray of all the objects whose .name property matches one of the names in the second NSArray.
How do I go about this, fast and efficiently as this will be required quite often.
Why not just to use predicates to do that for you?:
// For number kind of values:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF = %#", value];
NSArray *results = [array_to_search filteredArrayUsingPredicate:predicate];
// For string kind of values:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[cd] %#", value];
NSArray *results = [array_to_search filteredArrayUsingPredicate:predicate];
// For any object kind of value (yes, you can search objects also):
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", value];
NSArray *results = [array_to_search filteredArrayUsingPredicate:predicate];
Here's a simple way:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == %#", nameToFind];
[listOfItems filteredArrayUsingPredicate:predicate];
With your current data structures, you can only do it in O(n^2) time by looping over the first array once for each member of the second array:
NSMutableArray * array = [NSMutableArray array];
for (NSString * name in names) {
for (MyObject * object in objects) {
if ([[myObject name] isEqualToString:name]) {
[array addObject:object];
}
}
}
(Alternate as suggested by Stefan: loop over the objects array and ask the names array if it containsObject: for the name of each object.)
But if this really needs to be faster (really depends on the size of the arrays as much as how often you do it), you can improve this by introducing an NSDictionary that maps the names in the first array to their objects. Then each of those lookups is O(1) and the overall time is O(n). (You'd have to keep this dictionary always in sync with the array of objects, which isn't hard with reasonable accessors. This technique also has the constraint that the same name can't appear on more than one object.)
An alternate way of getting this result (and which doesn't have that last constraint) is to use an NSSet for your second collection, then walk through the objects array calling containsObject: with each one on the set of names. Whether this technique is better depends on whether your two collections are roughly the same size, or if one is much larger than the other.
I like to use this method:
NSIndexSet *indexes = [_items indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return ((MyObject *)obj).name isEqualToString:name];
}];
if (indexes.count != 0) {
//extract your objects from the indexSet, and do what you like...
}
NSMutableArray * foundNames = [NSMutableArray array];
for (MyObject * objectWithName in objectCollection) {
if ([names containsObject:objectWithName.name]) {
[foundNames objectWithName];
}
}
The methods most helpful will be:
filteredArrayUsingPredicate:
and
indexesOfObjectsPassingTest:
The second one uses a code block, not available on iOS before 4.0
Both of these will be more efficient than iterating directly.
There's a good example here:
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxUsing.html
NSMutableArray* solutions = [NSMutableArray array];
for (Object* object in objects){
for (NSString* name in names){
if ([object.name isEqualToString:name]){
[solutions addObject:object];
break; // If this doesnt work remove this
}
}
}
int count=0;
if (range.location!=NSNotFound)
{
[searchindex addObject:[NSString stringWithFormat:#"%d",count]];
}