Filtering NSArray/NSDictionary using NSPredicate - iphone

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]];

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.

Objective C: Filter out results from NSMutableArray by a dictionary key's value?

I have a NSMutableArray like this :
(
{
City = "Orlando";
Name = "Shoreline Dental";
State = Florida;
},
{
City = "Alabaster ";
Name = Oxford Multispeciality;
State = Alabama;
},
{
City = Dallas;
Name = "Williams Spa";
State = Texas;
},
{
City = "Orlando ";
Name = "Roast Street";
State = Florida;
}
)
Now how can I sort this NSMutableArray to get the results corresponding to State "Florida"
I expect to get
(
{
City = "Orlando";
Name = "Shoreline Dental";
State = Florida;
},
{
City = "Orlando ";
Name = "Roast Street";
State = Florida;
}
)
I went for this code,but it displays again the prevous four dictionaries .
NSSortDescriptor *valueDescriptor = [[NSSortDescriptor alloc] initWithKey:#"Florida" ascending:YES];
NSArray * descriptors = [NSArray arrayWithObject:valueDescriptor];
NSArray * sortedArray = [arr sortedArrayUsingDescriptors:descriptors];
Try using a comparator block:
NSIndexSet *indices = [array indexesOfObjectsPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
return [[obj objectForKey:#"State"] isEqualToString:#"Florida"];
}];
NSArray *filtered = [array objectsAtIndexes:indices];
Alternatively, you can use a predicate as well:
NSPredicate *p = [NSPredicate predicateWithFormat:#"State = %#", #"Florida"];
NSArray *filtered = [array filteredArrayUsingPredicate:p];
If your array contains dictionary then you can use NSPredicate to filter out your array as follows:
NSPredicate *thePredicate = [NSPredicate predicateWithFormat:#"State CONTAINS[cd] Florida"];
theFilteredArray = [theArray filteredArrayUsingPredicate:thePredicate];
Assuming your array name is : arr
This one of the typical way to find, although a bit obsolete way....
for (NSDictionary *dict in arr) {
if ([[dict objectForKey:#"State"]isEqualToString:#"Florida"]) {
[filteredArray addObject:dict];
}
}
NSLog(#"filteredArray->%#",filteredArray);
Using predicates and blocks are already posted :)
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"State = %#", #"Florida"];
NSArray *filteredArray = [arr filteredArrayUsingPredicate:predicate];
NSLog(#"filtered ->%#",filteredArray);

NSPredicate exclude "name" in array

I have this array of names (listedName) that I want to filter out and remove in fbFriends array. How I can do it? Seems my clause is not working.
// add "names" to listed name array
NSMutableArray *aTempFriendList = [[NSMutableArray alloc] init];
for (int n = 0; n < [[self friendsList] count]; n++) {
NSDictionary *dFriend = [[self friendsList] objectAtIndex:n];
NSString *sName = [dFriend objectForKey:#"name"];
[aTempFriendList addObject:sName];
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(name not in %#)", aTempFriendList];
[fbFriends filterUsingPredicate:predicate];
It should be #"not (name in %#)".

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.

How retrieve an index of an NSArray using a NSPredicate?

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
}
}];