How retrieve an index of an NSArray using a NSPredicate? - iphone

I would know how retrieve an index of an NSArray using a NSPredicate ?
NSArray *array = [NSArray arrayWithObjects:
#"New-York City",
#"Washington DC",
#"Los Angeles",
#"Detroit",
nil];
Which kind of method should I use in order to get the index of "Los Angles" by giving only a NSString?
NB: #"Los An" or #"geles" should return the same index.

Using NSPredicate you can get array of strings that contain your search string (it seems there's no built-in method to get just element indexes):
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF CONTAINS[cd] %#", searchString];
NSArray *filteredArray = [array filteredArrayUsingPredicate: predicate];
You can get only indexes using indexesOfObjectsPassingTest: method:
NSIndexSet *indexes = [array indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){
NSString *s = (NSString*)obj;
NSRange range = [s rangeOfString: searchString];
return range.location != NSNotFound;
}];
If you want to get just one element containing your string you can use similar indexOfObjectPassingTest: method for that.

You should be able to do this with blocks. Below is a snippet (I don't have a compiler handy so pls excuse any typos):
NSArray *array = [NSArray arrayWithObjects:
#"New-York City",
#"Washington DC",
#"Los Angeles",
#"Detroit",
nil];
NSString *matchCity = #"Los";
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains[cd] %#", matchCity];
NSUInteger index = [self.array indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
return [predicate evaluateWithObject:obj];
}];
Essentially you can use the indexOfObjectPassingTest: method. This takes a block (code following the "^") and returns the index for the first object that matches your predicate (or NSNotFound if no match exists). The block iterates through each object in the array until either a match is found (at which point it returns the index) or no match is found (at which point it returns NSNotFound). Here is a link to block programming that can help you understand the logic within the block:
https://developer.apple.com/library/ios/featuredarticles/Short_Practical_Guide_Blocks/

Found an alternative approach helpful where the search is more complex as it allows predicate to be used to find object then object to find index:
-(NSIndexPath*) indexPathForSelectedCountry{
NSUInteger indexToCountry = 0;
NSPredicate * predicate = [NSPredicate predicateWithFormat:#"isoCode = %#",self.selectedCountry.isoCode];
NSArray * selectedObject = [self.countryList filteredArrayUsingPredicate:predicate];
if (selectedObject){
if (self.searchDisplayController.isActive){
indexToCountry = [self.searchResults indexOfObject:selectedObject[0]];
}else{
indexToCountry = [self.countryList indexOfObject:selectedObject[0]];
}
}
return [NSIndexPath indexPathForRow:indexToCountry inSection:0];
}

I would do this..
NSString * stringToCompare = #"geles";
int foundInIndex;
for ( int i=0; i<[array count]; i++ ){
NSString * tryString = [[array objectAtIndex:i] description];
if ([tryString rangeOfString:stringToCompare].location == NSNotFound) {
// no match
} else {
//match found
foundInIndex = i;
}
}// end for loop

Based on #Louie answer, instead of using for loop i had used enumeration block which worked for me.
I did this :-
NSString *stringToCompare = #"xyz";
[myArray enumerateObjectsUsingBlock:^(id *Obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSString * tryString = [[myArray objectAtIndex:idx] description];
if ([tryString rangeOfString:stringToCompare].location == NSNotFound) {
// no match found
} else {
//match found and perform your operation. In my case i had removed array object at idx
}
}];

Related

NSPredicate of NSArray in NSDictionary

My Array
(
{id:1,data:(#"macbook",#"mac mini")},
{id:2,data:(#"ipad",#"ipod")},
{id:3,data:(#"macbook",#"ipod")}
)
I have a predicate
NSString *text = #"mac";
[NSPredicate predicateWithFormat:#"(data contains[cd] %#)",text];
[array filteredArrayUsingPredicate:predicate];
but it doesn't loop over my array inside my dictionary
(my result should be an array containing 2 objects with id 1 and 3)
NSString* text = #"mac" ;
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"any data contains[cd] %#",text] ;
NSArray* filteredArray = [theArray filteredArrayUsingPredicate:predicate] ;
I personally find NSPredicate formats very error prone.
You may consider using a block in order to filter your NSArray
NSString * filterString = #"mac";
NSIndexSet * indexes = [array indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
NSArray * entry = obj[#"data"];
for (NSString * value in entry)
if ([value rangeOfString:filterString].location != NSNotFound)
return YES;
return NO;
}];
NSArray * filteredArray = [array objectsAtIndexes:indexes];
It's definitely longer and more verbose, but I find it definitely easier to read and debug.

Search String into NSArray based on charcters order?

My Problem Scenario is like this. I have an NSMutableArray ( Every Object is Nsstring). I have a UItextField ( as Client said) for Search.
I want know how to Search String into NSMutableArray like this
if I type A into textfield only those Content come from NSMutableArray which start From A.
if I type AB into TextField only those Content Comes from NSMutableArray which is started from AB..
....
I am Trying NSRange Concept I like share Mycode
~
for (int i=0; i<[[localTotalArrayForAwailable objectForKey:#"PUNCH"] count]; i++)
{
NSString *drinkNamePuch= [[[localTotalArrayForAwailable objectForKey:#"PUNCH"] objectAtIndex:i] drinkNames];
NSRange titleResultsRange = [drinkNamePuch rangeOfString:searchText options:( NSCaseInsensitiveSearch)];
if (titleResultsRange.length>0)
{
[searchArraypuch addObject:[[localTotalArrayForAwailable objectForKey:#"PUNCH"] objectAtIndex:i]];
[copyListOfItems setValue:searchArraypuch forKey:#"PUNCH"];
}
}
~
Based on this code search not working proper as i need.
Thanks
If you're trying to find all of the strings that match your searchText from the beginning, then you should check:
if ( titleresultsRange.location == 0 )
Other than that, I am not sure what is "not working proper", you need to provide a better explanation of what your expected results are, and what your actual results are.
Do this;
NSPredicate* predicate = [NSPredicate predicateWithFormat:#"SELF BEGINSWITH[cd] %#", searchText];
NSArray* filteredStrings = [[localTotalArrayForAwailable objectForKey:#"PUNCH"] filteredArrayUsingPredicate:predicate];
In filteredStrings you got all the strings that begins with searchText.
You might find Predicate Programming Guide helpful.
try this logic....it is working
NSMutableArray *arr = [[NSMutableArray alloc]initWithObjects:#"aa",#"bbb",#"bb",#"cc",#"dd",#"ee",#"ff",#"gg",#"hh",#"ii", nil];
NSMutableArray *arrNew = [[NSMutableArray alloc]init];
NSString *strSearch = #"cccc";
int k = strSearch.length;
for (int i=0; i<[arr count]; i++) {
for (int j=0; j<k; j++) {
if (k<=[[arr objectAtIndex:i] length]) {
if ([strSearch characterAtIndex:j] != [[arr objectAtIndex:i]characterAtIndex:j]) {
break;
}
else if(j == k-1){
[arrNew addObject:[arr objectAtIndex:i]];
}
}
}
}
NSLog(#"%#",[arrNew description]);
You can use these methods, which are provided by NSArray/NSMutableArray:
In NSArray see section "Finding Objects in an Array" for filtering methods starting with "indexesOfObjects...", e.g. indexesOfObjectsPassingTest:
In NSArray see section "Deriving New Arrays" for the method filteredArrayUsingPredicate:
In NSMutableArray there is a method filterUsingPredicate:
For narrowing the results you can continue applying the filtering consecutively to the filtered arrays or index sets.
Example with indexesOfObjectsPassingTest: using a block:
NSArray *strings = [NSArray arrayWithObjects:#"A", #"a", #"aB", #"AbC", #"Bag", #"Babc", #"baCK", #"", #"dba", nil];
NSString *searchString = #"Ab";
BOOL (^startsWithPredicate)(id, NSUInteger, BOOL*) = ^BOOL (id obj, NSUInteger idx, BOOL *stop) {
NSString *string = (NSString *) obj;
NSRange range = [string rangeOfString:searchString options:NSCaseInsensitiveSearch];
return (range.location == 0);
};
NSIndexSet *indexSet = [strings indexesOfObjectsPassingTest:startsWithPredicate];
NSLog(#"Strings found: %#", [strings objectsAtIndexes:indexSet]);
Output:
Strings found: (
aB,
AbC
)

Filtering NSArray/NSDictionary using NSPredicate

I've been trying to filter this array (which is full of NSDictionaries) using NSPredicate...
I have a very small amount of code that just isn't working...
The following code should change label.text to AmyBurnett34, but it doesn't...
NSPredicate *pred = [NSPredicate predicateWithFormat:#"id = %#", [[mightyPlistDict objectForKey:#"pushesArr"] objectAtIndex:indexPath.row]];
NSLog(#"%#",pred);
label.text = [[[twitterInfo filteredArrayUsingPredicate:pred] lastObject] objectForKey:#"screen_name"];
NSLog(#"%#",twitterInfo);
And here is what gets NSLoged...
2012-08-05 11:39:45.929 VideoPush[1711:707] id == "101323790"
2012-08-05 11:39:45.931 VideoPush[1711:707] (
{
id = 101323790;
"screen_name" = AmyBurnett34;
},
{
id = 25073877;
"screen_name" = realDonaldTrump;
},
{
id = 159462573;
"screen_name" = ecomagination;
},
{
id = 285234969;
"screen_name" = "UCB_Properties";
},
{
id = 14315150;
"screen_name" = MichaelHyatt;
}
)
Just for the heads up if you also NSLog this... the array is empty...
NSLog(%#,[twitterInfo filteredArrayUsingPredicate:pred]);
The problem is that your predicate is using comparing with a string and your content is using a number. Try this:
NSNumber *idNumber = [NSNumber numberWithLongLong:[[[mightyPlistDict objectForKey:#"pushesArr"] objectAtIndex:indexPath.row] longLongValue]];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"id = %#", idNumber];
You don't know for sure that the value of "id" is a string - it might be a NSNumber. I suggest:
NSUInteger matchIdx = ...;
NSUInteger idx = [array indexOfObjectPassingTest:^BOOL(NSDictionary *dict, NSUInteger idx, BOOL *stop)
{
id obj = [dict objectForKey:#"id"];
// NSLog the class if curious using NSStringFromClass[obj class];
NSUInteger testIdx = [obj integerValue]; // works on strings and numbers
return testIdx == matchIdx;
}
if(idx == NSNotFound) // handle error
NSString *screenName = [[array objectAtIndex:idx] objectForKey:#"screen_name"];
NSPredicate is used for filtering arrays, not sorting them.
To sort an array, use the sortedArrayUsingDescriptors method of NSArray.
An an example:
// Define a sort descriptor based on last name.
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"lastName" ascending:YES];
// Sort our array with the descriptor.
NSArray *sortedArray = [originalArray sortedArrayUsingDescriptors:[NSArray arrayWithObjects:descriptor, nil]];

Sort an NSString

i have an iOS application witch have a search bar and a UITableView. when i click in the search bar for example "ta", the web services return to me all the words witch contain "at",
for example "beta","mota","at work","ebebebatbcbcb" , i would like to have just the words witch begin with "at", not all the words witch contain "at".
Thanks for your answers.
try this:
-(NSMutableArray *)array:(NSMutableArray *)array withstart:(NSString *)string{
NSPredicate *sPredicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#",string];
[array filterUsingPredicate:sPredicate];
return array;
}
Or other way:
NSString *prefix = #"at";
NSArray *final_array=[array objectsAtIndexes:[array indexesOfObjectsPassingTest:^(id obj, NSUInteger idx, BOOL *stop)
{
return [obj hasPrefix:prefix];
}]];
NSPredicate is the way to go:
NSString *searchTerm = #"ta";
NSArray *matchingKeywords = [result filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF beginswith[cd] %#",searchTerm]];
Heres a simple answer
NSString *prefix = #"at";
[array objectsAtIndexes:[array indexesOfObjectsPassingTest:^BOOL(NSString *string, NSUInteger idx, BOOL *stop) {
return [string hasPrefix:prefix];
}]];
Sounds like a job for NSPredicate!

How to search in NSArray?

I am having an array like fallowing,
NSArray*array = [NSArray arrayWithObjects:#"1.1 something", #"1.2 something else", #"1.3 out of left field", #"1.4 yet another!", nil];
Now,i am having the string like fallowing,
NSString*str = #"1.3";
Now i will send the str .Then it needs to find that str in array and it need to return the index of object where that text found.Means i need index 2 has to come as output.Can anyone share the code please.Thanks in advance.
Here is an example using blocks, notice the method: hasPrefix:
NSArray *array = [NSArray arrayWithObjects:#"1.1 problem1", #"1.2 problem2", #"1.3 problem3", #"1.4 problem4", nil];
NSString *str = #"1.3";
NSUInteger index = [array indexOfObjectPassingTest:
^(id obj, NSUInteger idx, BOOL *stop) {
return [obj hasPrefix:str];
}];
NSLog(#"index: %lu", index);
NSLog output:
index: 2
First a comment,
NSString *str = 1.3;
does not create an NSString object. You should instead have
NSString *str = #"1.3";
To search the NSArray, you will either have to change the string to the exact string in the array or search the NSString as well. For the former, simply do
float num = 1.3;
NSString *str = [NSString stringWithFormat:#"%.1f problem%d",num,(num*10)%10];
[array indexOfObject:str];
You can get fancier using NSPredicates as well.
Try
NSString *searchString = [str stringByAppendingFormat: #" problem%#", [str substringFromIndex: 2]];
NSUInteger index = [array indexOfObject: searchString];
Or (because you somehow like oneliners):
[array indexOfObject: [[array filteredArrayUsingPredicate: [NSPredicate predicateWithFormat: #"SELF beginswith %#", str]] objectAtIndex: 0]];
The simplest way is to enumerate through values of array and check substrings:
NSArray *array = [NSArray arrayWithObjects: #"1.1 something", #"1.2 something else", #"1.3 out of left field", #"1.4 yet another!", nil];
NSString *str = #"1.33";
int i = -1;
int index = -1;
for (NSString *arrayString in array) {
i++;
if ([arrayString rangeOfString: str].location != NSNotFound) {
index = i;
break;
}
}
NSLog(#"Index: %d", index);
Not optimal but will work.