Getting a values from array - ios

I have searchBar in my app,
What i want to do is when user types any character in searchBar, I want to get all the values starting with same character from my array.
Here is my code snippet i have tried but it crashes..
for (int i=0; i<[arr count]; i++) {
for(NSString *name in [[arr objectAtIndex:i] objectForKey:#"Merchant_Name"])
{
NSRange r = [name rangeOfString:searchText options:NSCaseInsensitiveSearch];
if(r.location != NSNotFound)
{
if(r.location== 0)//that is we are checking only the start of the naames.
{
[arr addObject:name];
}
}
}
}
Shows ERROR:-[__NSDictionaryM rangeOfString:options:]: unrecognized selector sent to instance
Where i am making mistake?
Please help and thanks in advance.
EDIT:
arr = {
"Merchant_Id" = 1036;
"Merchant_Name" = "Arzoo Hotels";
"Merchant_Url" = "arzoo-hotels";
},
{
"Merchant_Id" = 1037;
"Merchant_Name" = "Ashika Mall";
"Merchant_Url" = "ashika-mall";
},
{
"Merchant_Id" = 1038;
"Merchant_Name" = "At My Doorsteps";
"Merchant_Url" = "at-my-doorsteps";
},
{
"Merchant_Id" = 1039;
"Merchant_Name" = "AVA Host";
"Merchant_Url" = "ava-host";
},

For that, you should filter your array using NSPredicate.
Edit: Using predicate and filtering is much more readable and understandable. As stated in the comment, it might be slower, but you probably won't have 10,000,000+ strings you'd like to filter through, so saving 0.00001 second probably isn't worth writing a code 10 lines longer.
Documentation here.
And here's a whole tutorial about search bar and filtering data.
A quick example to filter an array and get values that begin with 'a' or 'c':
NSMutableArray *array =
[NSMutableArray arrayWithObjects:#"Nick", #"Ben", #"Adam", #"Melissa", nil];
NSPredicate *bPredicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] 'a'"];
NSArray *beginWithB = [array filteredArrayUsingPredicate:bPredicate];
// beginWithB contains { #"Adam" }.
NSPredicate *sPredicate = [NSPredicate predicateWithFormat:#"SELF contains[c] 'e'"];
[array filterUsingPredicate:sPredicate];

Using Below code you can do straight search
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"Merchant_Name LIKE[cd] '%#' ",searchText];
NSArray *filter = [arr filteredArrayUsingPredicate:predicate];
Using Below code you can do custom search
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"Merchant_Name beginswith[c] 'a'"];
NSArray *aNames = [arr filteredArrayUsingPredicate:predicate]
-use this code
-And Set Delegate to Uitextfield.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *changedText = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF['Merchant_Name'] contains %#",changedText];
NSArray *filter = [arraydata filteredArrayUsingPredicate:predicate];
NSLog(#"%#%",changedText);
return YES;
}

There is NSMutableDictionary type object in arr, try this to avoid crash:
for(NSString *name in arr){
if(![name isKindOfClass:[NSString class]]){
continue;
}
NSRange r = [name rangeOfString:searchText options:NSCaseInsensitiveSearch];
if(r.location != NSNotFound)
{
if(r.location== 0)//that is we are checking only the start of the naames.
{
[Array addObject:name];
}
}
counter++;
}

Related

Obj-C - Filter NSMutableArray with multiple objects?

I'm currently filtering an NSMutableArray (neighbourUIDs) with a value, but I now want to filter the same array with a second string as well, e.g.
[predicateString appendFormat:#"SELF.neighbourhood ==[c] '%1$#' OR %#", neighbourUIDs[i], hq];
That being said, when I attempt to write the above, XCode throws me the following error:
Cannot mix positional and non-positional arguments in format string
Any idea how I can accomplish this? See current code below:
ViewController.m
NSMutableArray *neighbourUIDs = [self.currentUser valueForKey:#"neighbourhood"];
NSMutableString *predicateString = [NSMutableString string];
for (NSInteger i = 0; i < [neighbourUIDs count]; i++) {
if (i != 0) {
[predicateString appendString:#" OR "];
}
NSString *hq = #"Headquarters";
[predicateString appendFormat:#"SELF.neighbourhood ==[c] '%1$#'", neighbourUIDs[i]];
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateString];
self.closeByNeighbours = [[self.neighbourData filteredArrayUsingPredicate:predicate] mutableCopy];

Using NSPredicate to filter a value in NSDictionary and return the keys array

I've a dictionary with a string value and an int key.
i.e.
{1,abc}
{2,bcd}
{3,cde}
I'm filtering it using NSPredicate as follows
NSMutableDictionary *tableDataSearch;
NSArray *searchResults;
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"self contains[cd] %#", searchText];
searchResults = [[tableDataSearch allValues] filteredArrayUsingPredicate:resultPredicate];
it is returning me the array of values which contain the specific word. I want all keys to be returned in the array and search in values like it is searching right now.
any help ?
suppose you have an array of dictionaries myArrayOfDict. and dictionary have differentes keys. this will with gives you all dictionnary where any value contains your string:
NSMutableArray* myArrayOfDict = [#[#{#"key1":#"value1"} , #{#"key2": #"value2"}]mutableCopy];
NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"ANY SELF.#allValues contains[cd] %#", #"lue1"];
NSArray *searchResults = [myArrayOfDict filteredArrayUsingPredicate:resultPredicate]; // will get the 2nd diction
The following code filters an NSDictionary based on a substring search on its values:
NSDictionary *data = #{#1 : #"abc",
#2 : #"bcd",
#3 : #"def"};
NSString *searchText = #"bc";
NSMutableDictionary *filteredData = [NSMutableDictionary new];
[data enumerateKeysAndObjectsUsingBlock:^(id key, NSString *obj, BOOL *stop) {
NSRange range = [obj rangeOfString:searchText
options:NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch];
if (range.location != NSNotFound)
{
[filteredData setObject:obj forKey:key];
}
}];
NSArray *keys = [filteredData allKeys];
If this feels a bit cumbersome, BlocksKit provides some useful extensions to NSDictionary:
NSDictionary *filteredData = [data bk_select:^BOOL(id key, NSString *obj) {
NSRange range = [obj rangeOfString:searchText
options:NSCaseInsensitiveSearch | NSDiacriticInsensitiveSearch];
return range.location != NSNotFound;
}];
And if you prefer to use NSPredicate, you can replace range.location != NSNotFound with:
[resultPredicate evaluateWithObject:obj];

Filter array of dictionaries by NSString

while implementing search functionality I need to filter array of dictionaries. I am using auto complete textfield method for search bar and am storing it into string. I can able to parse the array,But facing with below json
[{"CertProfID":"4","Name":"Dodge","Location":"loc4","City":"city4","State":"state4","Zip":"zip5","Website":"http:\/\/cnn.com","Phone":"phone4","Email":"email4"},
{"CertProfID":"5","Name":"cat","Location":"loc5","City":"city5","State":"State5","Zip":"zip5","Website":"web5","Phone":"phone5","Email":"email5"}]
Here I need to filter the dictionaries to make it finish
I tried with below code but its returning array with null values :(
NSString *substring = [NSString stringWithString:textField.text];
NSLog(#"substring %#",substring);
NSMutableArray *arr2Filt= [arraylist valueForKey:#"Name"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#",substring];
filteredarr = [NSMutableArray arrayWithArray:[arr2Filt filteredArrayUsingPredicate:predicate]];
This code will solve your problem it will return an array of dictionaries
NSString *substring = [NSString stringWithString:textField.text];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"Name contains[c] %#",searchString];
NSArray *filteredArry=[[arrayOfDict filteredArrayUsingPredicate:predicate] copy];
arrayOfDict is your original array of dictionaries
Swift 4.2 Version:::
let namePredicate = NSPredicate(format: "Name contains[c] %#",searchString)
let filteredArray = arrayOfDict.filter { namePredicate.evaluate(with: $0) }
print("names = \(filteredArray)")
Hope it will help you
You could use blocks instead. They are much less hand-wavy about match conditions.
NSString *substring = [NSString stringWithString:textField.text];
NSLog(#"substring %#",substring);
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return [evaluatedObject[#"Name"] containsString:substring];
}];
filteredarr = [NSMutableArray arrayWithArray:[arraylist filteredArrayUsingPredicate:predicate]];
Here one observation is that filteredArrayUsingPredicate is a method of NSArray and you are using NSMutableArray instead.
Change NSMutableArray with temporary NSArray object for predicate.
For example:
NSString *substring = [NSString stringWithString:textField.text];
NSArray *tempArray = [arraylist valueForKey:#"Name"];
// If [arraylist valueForKey:#"Name"]; line returns NSMutableArray than use below line
// NSArray *tempArray = [NSArray arrayWithArray:[arraylist valueForKey:#"Name"]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#",substring];
filteredarr = [[tempArray filteredArrayUsingPredicate:predicate] mutableCopy];
Hi I know there is many any answer,
In my case I have stored values As JSON MODEL object, This is code for, using JSON MODEL
NSString *searchString = searchBar.text;
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
NSDictionary *temp=[evaluatedObject toDictionary];
return [temp[#"user"][#"firstName"] localizedCaseInsensitiveContainsString:searchString];
}];
filteredContentList = [NSMutableArray arrayWithArray:[searchListValue filteredArrayUsingPredicate:predicate]];
[tableViews reloadData];
searchListValue is a NSMutableArray which contains Array of json model objects.If anyone need help regarding this, just ping me
Swift version above 2.2
var customerNameDict = ["firstName":"karthi","LastName":"alagu","MiddleName":"prabhu"];
var clientNameDict = ["firstName":"Selva","LastName":"kumar","MiddleName":"m"];
var employeeNameDict = ["firstName":"karthi","LastName":"prabhu","MiddleName":"kp"];
var attributeValue = "ka";
var arrNames:Array = [customerNameDict,clientNameDict,employeeNameDict];
//var namePredicate =
// NSPredicate(format: "firstName like %#",attributeValue);
//uncomment above line to search particular word
let namePredicate =
NSPredicate(format: "firstName contains[c] %#",attributeValue);
let filteredArray = arrNames.filter { namePredicate.evaluateWithObject($0) };
print("names = ,\(filteredArray)");
More about this refer here

Filtering a large NSArray with NSPredicate

I have an array containing 170k strings (words in a dictionary), and a string, looking something like "glapplega". I'm trying to extract the word "apple" from the string (with "apple" being a word in the array). I also need to make sure that the extracted word is at least 3 characters. The code I have right now is the following:
NSPredicate *wordPredicate = [NSPredicate predicateWithFormat:#"'%#' contains[cd] SELF", string];
NSPredicate *lengthPredicate = [NSPredicate predicateWithFormat:#"SELF.length > 2"];
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:#[wordPredicate, lengthPredicate]];
return [_words filteredArrayUsingPredicate:lengthPredicate];
The length predicate works on it's own, but the word predicate does not (it returns an empty array, despite "apple" being a word in the array).
I suspect that there might be a problem with using SELF as the right expression in the predicate, as all the examples I found have it as the left expression, although I have no way of confirming this.
Edit: I'm aware that this can likely be accomplished with regexs (as described here), but was hoping there would be a way around this, as regexs can be slow with such a large dataset.
Solving this problem is easy if you iterate the array yourself using a block predicate. At some point a formatted NSPredicate would have to boil down to this, so there shouldn't be much of a performance hit. -[NSString rangeOfString:] can be used to test for inclusion of the string.
return [_words filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL (id evaluatedString, NSDictionary *bindings) {
return string.length > 2 && [string rangeOfString:evaluatedString].location != NSNotFound;
}]];
You know what your above assumption and predicate is perfectly valid. The only thing that you have been doing wrong is quotations. Reformat your predicate and make it like this,
NSArray * array = #[#"Apple", #"lega", #"foo", #"bar"];
NSString *string = #"glapplega";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%# contains[cd] SELF and SELF.length > 2", string];
NSLog(#"%#",[array filteredArrayUsingPredicate:predicate]);
(
Apple,
lega
)
When you specify the format and supply the string to the format, the predicate places the quotes by itself. So, you have been mistaking over here.
#define rchar (rand() % ('z'-'a') + 'a')
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSMutableArray * mar = [NSMutableArray new];
for (int i = 0; i<170000; i++)
{
NSString * str = [NSString stringWithFormat:#"%c%c%c%c",rchar, rchar, rchar, rchar];
[mar addObject:str];
}
NSString * bigStr = #"asdfghjkl;loiuytrdcvcdrtgvfrtghvcftyghvfghcfdtyjghvncdfjtygmvcnfhjghjkgfhdgsxgrecrvtbkunhlmnhubkujvytchrtxgrecdjvbyhnkbjgcfhvyjhbghnkbjchgdfvbghnukbytvjycterwxrzewxcevfbjnkmjohgytreytwexkutckhtdtcfhvjgkjmhgcjhewwzsserdp9dlkuydssqwsxdchvggjhmgbj";
NSDate *start = [NSDate date];
NSArray * marFiltered = [mar filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return [bigStr rangeOfString:evaluatedObject].length>2;
}]];
NSLog(#"found %lu items in %f seconds", (unsigned long)[marFiltered count], -[start timeIntervalSinceNow]);
}
output:
2014-05-11 09:09:53.048 170k[89396:303] found 85 items in 0.542431 seconds
You can try two options for defining the predicate. A format string and a block. Here is a bit of code that demonstrates both. I've played a bit with both and can share that the performance is the same. I've only had the patience to run it with a max value of INT32_MAX/2 (a lot of items).
Here goes. Hope this clarifies and helps:
NSString* searchString = #"AB0";
NSUInteger capacity = 1000000;
NSMutableArray* array = [NSMutableArray array];
NSLog(#"Fillling array with %lu UUIDS. Be patient.", (unsigned long)capacity);
NSUInteger batch = 0;
for ( NSUInteger i = 0; i < capacity; i++ ) {
[array setObject:[[NSUUID UUID] UUIDString] atIndexedSubscript:i];
if (i != 0 && i % (capacity / 10) == 0 ) {
NSLog(#"Completed %lu%%", (unsigned long)++batch * 10);
}
}
NSLog(#"Done.");
NSPredicate* formatPredicate = [NSPredicate predicateWithFormat:#"SELF contains[cd] %# AND SELF.length > 3", searchString];
NSLog(#"Filtering with predicate: %#", formatPredicate);
NSArray* formatArray = [array filteredArrayUsingPredicate:formatPredicate];
NSLog(#"Got %lu results.", formatArray.count);
NSPredicate* blockPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
NSString* theString = evaluatedObject;
return theString.length > 3 && [theString rangeOfString:searchString].location != NSNotFound;
}];
NSLog(#"Filtering with predicate: %#", blockPredicate);
NSArray* blockArray = [array filteredArrayUsingPredicate:blockPredicate];
NSLog(#"Got %lu results.", blockArray.count);
PS: I wouldn't run this on a phone if you are using big numbers line INT32_MAX :)

Filter array by first letter of string property

I have an NSArray with objects that have a name property.
I would like filter the array by name
NSString *alphabet = [agencyIndex objectAtIndex:indexPath.section];
//---get all states beginning with the letter---
NSPredicate *predicate =
[NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alphabet];
NSMutableArray *listSimpl = [[NSMutableArray alloc] init];
for (int i=0; i<[[Database sharedDatabase].agents count]; i++) {
Town *_town = [[Database sharedDatabase].agents objectAtIndex:i];
[listSimpl addObject:_town];
}
NSArray *states = [listSimpl filteredArrayUsingPredicate:predicate];
But I get an error - "Can't do a substring operation with something that isn't a string (lhs = <1, Arrow> rhs = A)"
How can I do this? I would like to filter the array for the first letter in name being 'A'.
Try with following code
NSPredicate *pred = [NSPredicate predicateWithFormat:#"SELF like %#", yourName];
NSArray *filteredArr = [yourArray filteredArrayUsingPredicate:pred];
EDITED :
NSPredicate pattern should be:
NSPredicate *pred =[NSPredicate predicateWithFormat:#"name beginswith[c] %#", alphabet];
Here is one of the basic use of NSPredicate for filtering array .
NSMutableArray *array =
[NSMutableArray arrayWithObjects:#"Nick", #"Ben", #"Adam", #"Melissa", #"arbind", nil];
NSPredicate *sPredicate = [NSPredicate predicateWithFormat:#"SELF contains[c] 'b'"];
NSArray *beginWithB = [array filteredArrayUsingPredicate:sPredicate];
NSLog(#"beginwithB = %#",beginWithB);
NSArray offers another selector for sorting arrays:
NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(Person *first, Person *second) {
return [first.name compare:second.name];
}];
If you want to filter array take a look on this code:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name == %#", #"qwe"];
NSArray *result = [self.categoryItems filteredArrayUsingPredicate:predicate];
But if you want to sort array take a look on the following functions:
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context;
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context hint:(NSData *)hint;
- (NSArray *)sortedArrayUsingSelector:(SEL)comparator;
visit https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Collections/Articles/Arrays.html
use this
[listArray sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
Checkout this library
https://github.com/BadChoice/Collection
It comes with lots of easy array functions to never write a loop again
So you can just do
NSArray* result = [thArray filter:^BOOL(NSString *text) {
return [[name substr:0] isEqualToString:#"A"];
}] sort];
This gets only the texts that start with A sorted alphabetically
If you are doing it with objects:
NSArray* result = [thArray filter:^BOOL(AnObject *object) {
return [[object.name substr:0] isEqualToString:#"A"];
}] sort:#"name"];

Resources