IOS/Objective-C: Search string element with array of objects - ios

As part of an autocomplete box, I am searching names within an array of contacts. However, after the user picks a name from the suggested List, I need to grab the id of the contact which is in the array of contact objects but not the array of names that appear in the suggest box. I've been working with just the names as that's what I want to display in the suggestion box but have an array of contacts as well.
How would I convert code below (probably using key values) to search the name dimensions of an array of objects instead of an array of names so as to keep track of the ids of the objects. I am kind of fuzzy on arrays and key values.
//the array being searched looks something like #[#"John", #"Dave", #"Sam", #"Xian", #"Ahmed", #"Johann"];
//I want to search the names in an array that looks something like:
(
{
first = "John";cid = 2;},
{
first = "Dave";cid = 44;},
{
first = "Xian";cid=99})
//this code works great to search names but I lose track ids. Thank you for any suggestions.
-(void)searchArray: (NSMutableArray*) array forString: (NSString *) term {
[_contactsSuggested removeAllObjects];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#",term];
NSArray *tempArray = [array filteredArrayUsingPredicate:predicate];
_contactsSuggested = [NSMutableArray arrayWithArray:tempArray];
[_autocompleteTableView reloadData];
}

Create a Contact object. Give it a name property, an id property, and any other properties you need. Then write code that searches an array of Contact objects rather than just an array of names. You could then create a predicate using predicateWithBlock to filter the items that match your name property.

Related

Fetch Realm objects that contain parameter

I have a realm database filled with Restaurant objects that have a url parameter. I'd like to fetch the objects where the url contains what the user has typed in a UITextField.
NSPredicate *pred = [NSPredicate predicateWithFormat:#"url CONTAINS '%#'", self.searchQuery];
RLMResults<Database *> *results = [Database objectsWithPredicate:pred];
if ([results count] == 0) {
NSLog(#"results count == 0");
return nil;
}
Now, when I run this, I always get 0 results. Eventhough I have two example entries that have 'http://www.testingthis.com' as an url and the search query is 'testingthis'. Any ideas as to why I'm not getting results?
You need to perform your search query against the Restaurant class itself; not Database. Realm uses the class you specify to determine which table in which to apply the query.
As an aside, you can also inline NSPredicate queries with +[RLMObject objectsWhere:], so it's not necessary to create a separate NSPredicate object (unless you've got a specific reason). :)
RLMResults *restaurants = [Restaurant objectsWhere:#"url CONTAINS '%#'", #"testingthis"];
If you're trying to query for Restaurant objects that aren't in the default Realm, then you can alternatively use +[RLMObject objectsInRealm: where:] to explicitly control which database you're querying.

How can I implement my logic properly to populate my UITableView

Sorry guys, this problem I am running into is pretty trivial. I just can't wrap my head around it so hope someone can help me. Your help is really appreciated. I am getting JSON data through NSURLConnectDelegate with a web API. I get something like this back:
(
{
id = 340
name = Vicent },
{
id = 339
name = Johny },
{
id = 338
name = Eric }
)
and I save it in a NSMutableArray as a global variable. Now, I have a NSSet of "ids". For example:
{
340, 339
}
In the numberOfRowsInSection, I return the set's count. I am trying to load only the ids in the NSSet from the array with the data saved from the webAPI, so I do something like this in cellForRowIndexPath:
for (NSNumber *num in [set allObjects]) {
NSString *newString = [[savedArray objectAtIndex:indexPath.row]
NSString *new = [num stringValue];
if ([new isEqual:newString]) {
}}
How can I just populate the ids I want?
The JSON makes it look like you have an array of dictionaries, which is a reasonable data structure to use as the data source for a table view.
It sounds like you're trying to filter your array to only include the items that are in your set. Is that right?
If so, you could write code that would create a new array containing the subset of your array elements who's ID is also in your set. There are at least a half-dozen ways to do that. One fairly simple approach would be to use the NSArray method indexesOfObjectsPassingTest. You'd pass that method a block of code that would check each array element to see if it's id object was in your set.
That would give you an NSIndexSet with the indexes of the items in your array who's ID are in your set. Then you could use the NSArray method objectsAtIndexes to get an array of only the objects that are also in the set. Something like this (Assuming that your array of dictionaries is called savedArray and your set is called allObjects:
//get the indexes of items in the array savedArray who's id appears in the set allObjects
NSIndexSet *indexes = [savedArray indexesOfObjectsPassingTest:
^(NSDictionary *obj,
NSUInteger idx,
BOOL *stop)
{
return [allObjects member: obj[#"id"]] != nil;
}
];
//Now build an (immutable) array of just the objects who's ID are in the set
NSArray *subArray = [savedArray objectsAtIndexes: indexes];
The array subArray created above is immutable. If you need a mutable array you would need to make a mutable copy, which is a one-line change.
Disclaimer: I still struggle a little with block syntax, so the above might not be exactly correct, but it gives you the general idea.

how to compare only selected strings in a text with given input in objective-c

i know that the question sounds wears.I couldn't find a better way to put it so i will take my time to explain the question i m struggling with.
I have an iPhone app that takes input from user.And i got a plist ( i will convert it to a online database soon) What i currently do is this. I compare my input string with ingredients part of items in my plist.
This is the plist format
<array>
<dict>
<key>category</key>
<string>desert</string>
<key>numberOfPerson</key>
<string>3</string>
<key>recipeImage</key>
<string>asd.jpg</string>
<key>time</key>
<string>15</string>
<key>recipeName</key>
<string>Puding</string>
<key>recipeDetail</key>
i compare the input with recipeIngredients.But what my codes do is not what i need.If the comparison turns true i just list every item from my plist that contain the input ingredients.I can filter through selected recipes but what i want is this: Unless there is a full match up with input and ingredients i do not want to show it.
The problem is this. I got my recipe ingredients like this format 1 spoon of sugar, 1 spoon of salt, 100g chicken.
The user enter inputs like - salt , sugar. chicken so i can not fully compare it.It will never be the same so i can not show anything.
How can i accomplish this.
i m open for any kind of suggestions.
This is how i compare
results = [arrayOfPlist filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
NSDictionary *_dataRow = (NSDictionary *)evaluatedObject;
return ([[[_dataRow valueForKey:#"recipeIngredients"] lowercaseString] rangeOfString:[searchText lowercaseString]].location != NSNotFound);
}]];
where searchText is my input.
First of all, you'll never know if there is a typo in user input.
But what you can do is before you compare two strings, you can do a little bit trimming for a given character set.
There is a method in NSString class called :
- (NSString *)stringByTrimmingCharactersInSet:(NSCharacterSet *)set
If you want to get rid of . or - characters, you need to specify them in your character set. Than, you can compare two strings.
Using -[NSPredicate predicateWithFormat:] you can do database-esque string comparisons. For instance, you could try
[NSPredicate predicateWithFormat:#"recipeIngredients CONTAINS[cd] %#", searchText]
Check out https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html the section called "String Comparisons"
EDIT: if the user will be searching multiple things at once, like "chicken, noodle," you can be a little more fancy and do:
NSArray *tokens = [[searchText componentsSeparatedByCharactersInSet:NSCharacterSet.alphanumericCharacterSet.invertedSet] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"length > 0"];
NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:#"recipeIngredient CONTAINS[cd] (ANY %#)", tokens]
You should split up the searchText into an array by using -componentsSeparatedByString:#",", and then loop through the array to see if the recipeIngredients contains any of the ingredients in the searchText array. In order to work out if the query contains every single ingredient, you can create an integer inside of the block and increment it everytime you have a match. If the number of matches is equal to the number of ingredients, then you can go from there.
The code below builds up a predicate that boils down to "ingredients contains sugar and ingredients contains chocolate"
NSArray* recipes = #[
#{#"recipeIngredients": #"sugar flour chocolate"},
#{#"recipeIngredients": #"sugar chocolate"},
#{#"recipeIngredients": #"flour chocolate"},
#{#"recipeIngredients": #"chocolate"},
];
NSString* search = #"sugar, chocolate";
// split the ingredients we have into an array of strings separated by ',' or ' '
NSArray* haves = [search componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#", "]];
// Build a list of recipeIngredients CONTAINS have
NSMutableArray* ands = [NSMutableArray new];
for(NSString* have in haves)
{
if(have.length > 0)
{
[ands addObject:[NSPredicate predicateWithFormat:#"recipeIngredients CONTAINS[cd] %#", have]];
}
}
// String all the haves into a single long ... AND ... AND ... predicate
NSPredicate* predicate = [NSCompoundPredicate andPredicateWithSubpredicates:ands];
// Apply the predicate
NSArray* filtered = [recipes filteredArrayUsingPredicate:predicate];

Error when trying to sort array using predicates

I'm struggeling with an error occurring when trying to populate an array with the filtered results of another array.
I've defined a global array named allArray in the .h-file, this array is containing about 100 objects. Then, I want the user to be able to search for a specific object, and I've tried to develop it using predicates:
-(IBAction)searchChanged:(id)sender {
//The searchfield's value has been changed.
NSString *searchString = searchField.text;
NSPredicate *searchPredicate = [NSPredicate predicateWithFormat:#"self CONTAINS[c] %#", searchString];
NSMutableArray *tempSearchArray = [allArray filterUsingPredicate:searchPredicate];
[filteredArray removeAllObjects];
[filteredArray addObjectsFromArray:tempSearchArray];
}
I end up getting an error when I create tempSearchArray.
Initializing 'NSMutableArray *__strong' with an expression of
incompatible type 'void'
filterUsingPredicate doesn't return an array, it returns nothing(void).
From the description:
"Evaluates a given predicate against the array’s content and leaves only objects that match"
You should instead use:
filteredArrayUsingPredicate
As the Docs will tell you, filterUsingPredicate has a void return value.
See here:
NSMutableArray Class reference
That means that you cannot assign that return value to another array.
You need to use this method on the original array, along the lines of
[allArray filterUsingPredicate:somePredicate];
arrArray will be stripped of any elements that dont match the predicate.
Now proceed with these results as you wish.
Have Fun
filterUsingPredicate returns a void and not an array. You might want to consider using a filteredArrayUsingPredicate instead

NSPredicate filter array but return only one field of an object

I'm sure this question has been asked but I don't know what to search on.
I have array of Message objects with the following fields {selected[BOOL], messageText[STR]}. I want to filter this array to get only the objects with selected=TRUE. So far so good.
NSArray *messagesFiltered = [self.fetchedResultsController.fetchedObjects filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"selected == TRUE"]];
However, I don't need the objects themselves in the returned array, I need an array of the messageText strings. How to modify predicate to return only the messageText strings and not the whole object?
That's not really the job of a predicate. Predicates are only for filtering, not modifying, the array you apply them to.
However, there's a fun little trick: the method -valueForKey: will apply the kind of transform you want to your array. Just call it with the messageText key that you want:
NSArray *messagesFiltered = [self.fetchedResultsController.fetchedObjects filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"selected == TRUE"]];
NSArray *realMessages = [messagesFiltered valueForKey:#"messageText"];
On an array, -valueForKey: asks each element for a value for the given key, then returns an array of everything the elements returned. (Any element that returns nil for the key you pass shows up as [NSNull null] in the resulting array.)

Resources