I have a Core Data object Contact
Contact
=======
fullName
I'm using a NSFetchedResultsController to show a list of contacts.
I now want to add search option that behave as follow:
If user search for the string "da", the results should be:
Aaron David
Bert Daniels
Dana
John David
So the search result is alphabetic sorted strings that has a word starting with "da"
I remember watching a WWDC session showing how to create a Word object and store each word independently, but I'm trying to avoid this approach.
So my question is, can I do such a search with my current model structure and some predicate magic, or I must store the fullName as separate words?
This is what I do:
NSMutableArray *predicateArray = [NSMutableArray array];
if(searchString.length)
{
for (NSString* searchStringPart in [searchString componentsSeparatedByString:#" "])
{
if([searchStringPart length] > 0)
{
[predicateArray addObject:[NSPredicate predicateWithFormat:#"name CONTAINS[cd] %#", searchStringPart]];
}
}
filterPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:#[filterPredicate, [NSCompoundPredicate andPredicateWithSubpredicates:predicateArray]]];
}
And for sorting:
NSSortDescriptor *sort = [[[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES] autorelease];
NSArray* sortDescriptors = #[sort];
....
[fetchRequest setSortDescriptors:sortDescriptors];
You need to use predicate for filtered word by name in your array. Use below:-
//Assuming you have store the name in one array
NSArray *names=#[#"Aaron David",#"Bert Daniels",#"Dana",#"John David"];
//Now use contains in predicate for filtered words
//On the basis of search string it will filtered accordingly. lets Say yourStringValue=#"on"
NSPredicate *pd=[NSPredicate predicateWithFormat:#"self CONTAINS[CD] %#",yourStringValue];
NSArray *ar=[names filteredArrayUsingPredicate:pd];
NSLog(#"%#",ar);
Output:-
"Aaron David"
Related
I am trying to construct a query of a Core Data store which retrieves an entity's attribute values when they occur in longer string;
i.e, instead of seeking instances where attribute value contains a (shorter) string :
request.predicate = [NSPredicate predicateWithFormat:#"carBrand contains[c] 'merced'"]
I want to find instances (of the entity) whose attribute values are found 'contained in' an arbitrary (longer) string :
NSString* textString = #"Elaine used to drive Audis, but now owns a Mercedes";
request.predicate = [NSPredicate predicateWithFormat:#"%# contains[c] carBrand", textString ];
(ie. retrieve array holding objects with carBrand = #"Audi" and carBrand = #"Mercedes")
In my attempts, NSPredicate doesn't seem to like expressions with the attribute name on the right hand side and throws an error...
[__NSCFConstantString countByEnumeratingWithState:objects:count:]:
unrecognized selector sent to instance 0x
...is there a way of constructing such a query with the attribute name on the left hand side - a 'contained_by' query, as it were?
PS. Searching SO, I've only found solutions by splitting the text into component words which, in my scenario, would be less than ideal! Is this the only type of approach that's viable?
Build a regex string with your array and use MATCHES in your predicate.
[NSPredicate predicateWithFormat:#"%# MATCHES '*(Audi|Mercedes)*'", testString];
To filter cars based on their brand:
NSArray *brands = [#"Audi", #"Mercedes"];
[NSPrediate predicateWithFormat:#"carBrand IN %#", brands];
Decided to try implementing a componentsSeparatedByString approach to build a NSCompoundPredicate
//find alphabetic words omitting standard plurals
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(?:[^a-z]*)([a-z]+?)(?:s)?\\W+" options:NSRegularExpressionCaseInsensitive error:nil];
//separate with pipe| and split into array
NSString *split = [regex stringByReplacingMatchesInString:textString options:0 range:NSMakeRange(0, speciesString.length) withTemplate:#"$1|"];
NSArray *words = [split componentsSeparatedByString:#"|"];
//build predicate List
NSMutableArray *predicateList = [NSMutableArray array];
for (NSString *word in words) {
if ([word length] > 2) {
NSPredicate *pred = [NSPredicate predicateWithFormat:#"brandName beginswith[c] %#", word];
[predicateList addObject:pred];
}
}
//CarBrand* object;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"CarBrand" inManagedObjectContext:self.managedObjectContext];
request.predicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicateList];
NSError *error =nil;
NSArray *results = [self.managedObjectContext executeFetchRequest:request error:&error];
This retrieves the instances found in the text;
eg1:
#"Elaine used to drive Audis, but now owns a Mercedes";
gives array of objects whose .brandname = "Audi", "Mercedes", respectively .
eg2: #"Among the cars stolen were a Ford Mondeo, a Fiat 500C and an
Alfa-Romeo Spyder"
yields .brandname = "Ford", "Fiat",and "Alfa Romeo"(NB no '-') respectively.
I'm not yet accepting my own answer as it seems too much of a workaround and won't easily extend to (for example) extracting brand-name AND, say, model.
Hopefully, someone will have a better solution!
I have a simple Core Data model with two string attributes (size and category). Given a search string like 'small widget' is it possible to return records that match all the query words to at least one attribute (i.e. all records with 'small' size and 'widget' category)? I currently have:
NSString *search = #"small widget"
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"size contains[cd] %# OR category contains[cd] %#", search, search];
...
This won't return any results (as no category or size equals "small widget"). Any suggestions? Note that the search strings will be user entered from a text field and may come in any order so I can't split up manually.
I haven't tested it but it looks like your want this:
NSString *search = #"small widget";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%# contains[cd] size AND %# contains[cd] category", search, search];
The search string would contain (or not) the size and the category, you should ask if the current size or category is contained on the search string.
You could also split the search string and modify your predicate. You should them to identify the one that performs better
NSString *search = #"small widget";
NSArray *array = [search componentsSeparatedByString:#" "];
NSMutableArray *subPredicates = [NSMutableArray array];
for (NSString *q in array) {
[subPredicates addObject:
[NSPredicate predicateWithFormat:#"size contains[cd] %# OR category contains[cd] %#", q, q]];
}
NSCompoundPredicate *predicate = [[[NSCompoundPredicate alloc] initWithType:NSAndPredicateType
subpredicates:subPredicates] autorelease];
For Swift you can fetch multiple columns by using propertiesToFetch
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "<YOUR ENTITY NAME>")
let predicate = NSPredicate(format: "<YOUR PREDICATE>")
fetchRequest.predicate = predicate
fetchRequest.resultType = .dictionaryResultType
// Here is where you can query multiple columns, you can add as much columns as you want and fetch them as an array of dictionaries
fetchRequest.propertiesToFetch = ["column1", "column2", "column3, "column4"]
let sort = NSSortDescriptor(key: "column1", ascending: false)
fetchRequest.sortDescriptors = [sort]
Currently trying to setup a search would search an Array (bakeryProductArray) which looks like this
"Tea Loaf",
Tiramusu,
"Treacle Loaf",
Trifle,
"Triple Chocolate Brownie",
Truffles,
"Various sponges",
"Viennese Whirls",
"Wedding Cakes"
with what the users types into the UISearchbar. I am unclear on how to represent each item in the array in the CFString.
The code I currently have is.
-(void)filterContentForSearchText:(NSString *)searchText scope:(NSString *)scope
{
searchSearch = [NSPredicate predicateWithFormat:#"self CONTAINS[cd]",searchText];
//#"%K CONTAINS[cd] %#"
searchResults = [bakeryProductArray filteredArrayUsingPredicate:searchSearch];
NSLog(#"Filtered Food Product Count --> %d",[searchResults count]);
}
Can answer any questions and supply more code if needed.
Is this what your are looking for?
NSArray *bakeryProductArray = #[#"Tea Loaf", #"Tiramusu", #"Treacle Loaf", #"Trifle"];
NSString *searchText = #"tr";
NSPredicate *searchSearch = [NSPredicate predicateWithFormat:#"self CONTAINS[cd] %#", searchText];
NSArray *searchResults = [bakeryProductArray filteredArrayUsingPredicate:searchSearch];
NSLog(#"%#", searchResults);
// "Treacle Loaf",
// Trifle
This finds all strings that contain the given search string (case insensitive).
Alternatively, you can use "=" or "BEGINSWITH", depending on your needs.
(More information about predicates in the "Predicate Programming Guide" .)
I have an app using coreData fine.
I have this relationship:
company <--->> visitors
now, I need to find specific visitors for an specific company, I can fetch visitors starting with some string pattern,
But how to find the ones for a specific company?
here my code
- (void)searchAvailableDataFullName:(NSTimer*)timer
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"fullName BEGINSWITH [c] %#",self.nameTF.text];
//sort descriptor!
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"fullName" ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)];
//the relationship of interest??
Visitor *theVisitor = nil;
theVisitor.company = self.selectedCompany;
NSMutableArray *fullNamesArray = [NSMutableArray arrayWithArray:[Visitor allWithPredicate:predicate sortDescriptors:#[sortDescriptor]]];
Visitor *visitorName;
NSMutableArray *dataArray = [NSMutableArray array];
for (visitorName in fullNamesArray) {
NSLog(#"tus visitors:: %#", visitorName.fullName);
[dataArray addObject:visitorName.fullName];
}
}
I don't have my Mac in front of me atm but it should be something like:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"visitors.fullName BEGINSWITH [c] %# && visitors.CompanyName BEGINSWITH [c] %#",self.nameTF.text, companyNameTextObject];
Hope that's 100% right, if not you can kind of get the gist of it. You can use the "table.relationshipProperty" to search the relationship.
Apple Predicate Programming Guide
There's some more info there, just check out the "Joins" section. Hope that helps!
Hey i want to filter an NSArray. In this Array is a lot of information like name, town, telephonenumber, and so on. But some towns are twice or three times in the array.
I have property with a town in it.
So i want only those objects from the arry which match with the property.
For example:
in the Array stands:
Frank, New York, 123456
Oliver, New York, 123456
Thomas, Boston, 123456
and when the property is New York i want olny objects 1 and 2.
Does anyone has an idea how i can do it?
This is my code:
NSString *filterString = newsArticle;
NSPredicate *prediacte = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"Ort == '%#'",filterString]];
newsTownArray = [news filteredArrayUsingPredicate:predicate];
and when i come to the line:
cell.textLabel.text=[[newsTownArray objectAtIndex:indexPath.row] objectForKey:"Name"];
You need to use NSPredicate for this.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"town == 'New York'"];
[yourArray filterUsingPredicate:predicate];
Dynamically you can create predicate like:
NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"town == '%#'",yourInput]];
Here yourInput is a NSString which holds the required town name.
Please check these articles for more details:
codeproject
useyourloaf
Use this code
NSMutableArray *subpredicates = [NSMutableArray array];
for(NSString *term in arryOfWordsToBeSearched) {
NSPredicate *p = [NSPredicate predicateWithFormat:#"self contains[cd] %#",term];
[subpredicates addObject:p];
}
NSPredicate *filter = [NSCompoundPredicate andPredicateWithSubpredicates:subpredicates];
result = (NSMutableArray*)[arryOfDummyData filteredArrayUsingPredicate: filter];
However you can do it within an array with the use of NSPredicate, but I will suggest to do bit differently, this will add up to your code and good programming way.
Create a custom class Person having these properties name, city and telephone.
Create an array that will store objects of Person.
After this you can manipulate/ filter / sort etc quite easily.
NSString *filterCity=#"Delhi";
NSMutableArray *yourArray=[NSMutableArray arrayWithArray:self.persons];
NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"city == '%#'",filterCity]];
[yourArray filterUsingPredicate:predicate];
NSLog(#"Filtered");
for (Person *per in yourArray) {
NSLog(#"Name: %#, City: %#, Telephone: %#",per.name, per.city, per.telephone);
}