filter dictionary array by property that matches a different array - objective-c

I have two arrays and I'm trying to filter the first (array1) with a matching property that exists in a second array (array2). The first array is a dictionary array with key 'name'. The second array is an array of objects with property 'name'. Is it possible to filter contents of 'array1' and display only those that have a matching 'name' found in 'array2'?
I've tried:
NSPredicate *pred = [NSPredicate predicateWithFormat:#"name == #%",self.array2];
NSArray *results = [array1 filteredArrayUsingPredicate:pred];
NSLog(#"The results array is %#", results);
Rather than '==' I've tried a mix of 'IN' and '#K' and 'self' but it either crashes or results are 0.

NSPredicate *pred = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return [[array2 valueForKey:#"name"] containsObject:[evaluatedObject objectForKey:#"name"]];
}];

This should work with IN:
NSArray *matchSet = [self.array2 valueForKey:#"name"];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"name IN #%",matchSet];
Typed in Safari.
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html#//apple_ref/doc/uid/TP40001795-215891

Here's a quick example of how you could accomplish this:
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSArray *arrayOne = #[#{#"name": #"Alvin"}, #{#"name": #"Brian"}, #{#"name": #"Charlie"}];
BMPPerson *alvin = [[BMPPerson alloc] initWithName:#"Alvin"];
BMPPerson *charlie = [[BMPPerson alloc] initWithName:#"Charlie"];
NSArray *arrayTwo = #[alvin, charlie];
NSArray *values = [arrayTwo valueForKey:#"name"];
NSMutableArray *filteredValues = [NSMutableArray array];
[arrayOne enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString *name = [obj valueForKey:#"name"];
if ([values containsObject:name]) {
[filteredValues addObject:name];
}
}];
NSLog(#"%#", filteredValues);
}
return 0;
}
In the example, arrayOne is an NSArray of NSDictionary objects. Each object has a key of name.
The objects contained in arrayTwo are a basic NSObject subclass that has a name property.
To get the values of the name properties for all of the objects in arrayTwo we make use of the key-value coding method -valueForKey: which calls -valueForKey: on each object in the receiver and returns an array of the results.
We then create an NSMutableArray to hold the filtered results from arrayOne.
Next we enumerate the objects in arrayOne using the -enumerateObjectsUsingBlock: method. In this example, we know that the obj argument is an NSDictionary that has a key of name. Instead of casting to an NSDictionary and calling -objectForKey: we can simply call -valueForKey: and store the value in our local variable name. We then check to see if name is in the values array and if it is, add it to our filteredValues.

Related

Removing elements with same value from NSMutableArray

My NSMutableArray contains some strings as elements. One of the element is repeated many times at different indexes in the array. For example [#"", #"1,2,3",#"",#"5,3,2,1",#""].
I want to remove all the elements with value #"" from the mutable array. I tried following ways but couldn't get the solution.
Using For loop:
for(id obj in myMutableArray)
{
if([obj isEqualToString:#""])
{
[myMytableArray removeObject:obj];
}
}
Using dummy mutable array called nextMutableArray
for(id obj in myMutableArray)
{
if([obj isEqualToString:#""])
{
continue;
}
else [nextMutableArray addObject:obj];
}
In both the ways, elements (#"") at other indexes are removed but not at the index 0 (first object). What could be the possible reason? Is there any way to remove all the elements that contain string #"" from the mutable array?
one option is to filter your array using predicates:
NSArray *someArray = #[#"", #"1,2,3", #"", #"5,3,2,1", #""];
NSLog(#"%#", someArray);
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF != ''"];
NSArray *filteredArray = [someArray filteredArrayUsingPredicate:predicate];
NSLog(#"%#", filteredArray);
No Need of For loop. Simply use this.
[mutableArray removeObjectIdenticalTo:#""];
If you want to remove duplicate entries from an array, You can use NSSet Class.
NSSet did not accept duplicate/s value.
NSMutableArray *arrTest=[[NSMutableArray alloc]initWithObjects:#"", #"1,2,3",#"",#"5,3,2,1",#"", nil];
NSSet *set = [NSSet setWithArray:arrTest];
arrTest = [[set allObjects] mutableCopy];
or
You can do like this:
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id str, NSDictionary *unused) { return ![str isEqualToString:#""]; }];
arrTest = [[arrTest filteredArrayUsingPredicate:predicate]mutableCopy];
This is fast and simple way.

NSPredicate, search in a NSArray, inside a NSArray of NSDict

I have a NSArray of NSDictionary.
One of the keys of the NSDictionary contains a NSArray of strings.
Is there a way that I can use NSPredicate to find a specific strins in that Array of strings?
Thanks :)
Also: This work great, but not for sublevelArray
predicate = [NSPredicate predicateWithFormat:#" %K LIKE[cd] %#", sKey, sLookForString];
Just replace LIKE with CONTAINS in your format string. For example, given this array:
NSArray *dogs = #[#{#"name" : #"Fido",
#"toys" : #[#"Ball", #"Kong"]},
#{#"name" : #"Rover",
#"toys" : #[#"Ball", #"Rope"]},
#{#"name" : #"Spot",
#"toys" : #[#"Rope", #"Kong"]}];
...the following predicate can be used obtain a filtered array containing only the dictionaries where the value for the key toy is an array that contains the string Kong.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K CONTAINS[cd] %#", #"toys", #"Kong"];
On NSArray you can use filteredArrayUsingPredicate:, on NSDictionary use enumerateKeysAndObjectsUsingBlock: and then for each value do either a filteredArrayUsingPredicate: if it is an NSArray or you can use evaluateWithObject: using the predicate itself.
If you want to filter the array of dictionaries based on the array of strings, you can use -predicateWithBlock to filter the array, as shown in the code below:
- (NSArray *)filterArray:(NSArray *)array WithSearchString:(NSString *)searchString {
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
NSDictionary *dictionary = (NSDictionary *)evaluatedObject;
NSArray *strings = [dictionary objectForKey:#"strings"];
return [strings containsObject:searchString];
}];
return [array filteredArrayUsingPredicate:predicate];
}

NSMutableArray search string

I've a person object which has NSString properties firstname, lastname, birthday, and NSMutableDictionary of different phone numbers of that person.
I've added different person objects in an NSMutableArray named personArray.
Try using this method on NSArray. Something like this:
return [personArray[[personArray indexOfObjectPassingTest:^ (id obj, NSUInteger index, BOOL stop) {
return [lastName isEqualToString:[obj lastName]];
}]] phoneNumber];
You get the idea.
You should be able to do it like this:
-(NSArray *) phoneNumberFor:(NSString *)lastName{
NSInteger indx = [self.personArray indexOfObjectPassingTest:^BOOL(Person *aPerson, NSUInteger idx, BOOL *stop) {
return [aPerson.lastname isEqualToString:lastName];
}];
if (indx != NSNotFound) {
return [self.personArray[indx] phoneNumbers].allValues;
}else{
return nil;
}
}
In this example, I'm assuming an array property called personArray, a class name of "Person" for your person objects, and a mutable dictionary called phoneNumbers. I'm also assuming that the dictionary contains several keys and values, where all of the values are phone numbers.
You can get object from array of the given lastname like as follow:-
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"lastname == '%#'", lastname];
NSArray *foundPersonArray = [personArray filteredArrayUsingPredicate:predicate];
NSLog("found person object = %#",foundPersonArray);
But if you want to search multiple object of same lastname from array then you can do following:-
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"lastname LIKE[c] %#", lastname];
NSArray *foundPersonArray = [personArray filteredArrayUsingPredicate:predicate];
NSLog("found person object = %#",foundPersonArray);

Searching NSArray using suffixes

I have a word list stored in an NSArray, I want to find all the words in it with the ending 'ing'.
Could someone please provide me with some sample/pseudo code.
Use NSPredicate to filter NSArrays.
NSArray *array = #[#"test", #"testing", #"check", #"checking"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF ENDSWITH 'ing'"];
NSArray *filteredArray = [array filteredArrayUsingPredicate:predicate];
Let's say you have an array defined:
NSArray *wordList = // you have the contents defined properly
Then you can enumerate the array using a block
// This array will hold the results.
NSMutableArray *resultArray = [NSMutableArray new];
// Enumerate the wordlist with a block
[wordlist enumerateObjectsUsingBlock:(id obj, NSUInteger idx, BOOL *stop) {
if ([obj hasSuffix:#"ing"]) {
// Add the word to the result list
[result addObject:obj];
}
}];
// resultArray now has the words ending in "ing"
(I am using ARC in this code block)
I am giving an example using blocks because its gives you more options should you need them, and it's a more modern approach to enumerating collections. You could also do this with a concurrent enumeration and get some performance benefits as well.
Just loop through it and check the suffixes like that:
for (NSString *myString in myArray) {
if ([myString hasSuffix:#"ing"]){
// do something with myString which ends with "ing"
}
}
NSMutableArray *results = [[NSMutableArray alloc] init];
// assuming your array of words is called array:
for (int i = 0; i < [array count]; i++)
{
NSString *word = [array objectAtIndex: i];
if ([word hasSuffix: #"ing"])
[results addObject: word];
}
// do some processing
[results release]; // if you're not using ARC yet.
Typed from scratch, should work :)

Searching on the properties of objects in an array

I have an NSArray of objects with properties such as firstName, lastName, clientID etc. and i would like to perform a search on the array based on a search keyword. This keyword must be checked against the first name and the last name properties and return a subset of the original array that contains only those objects whose first/last name contain the search term. Is there any efficient/fast way to do this?
As a second thought, I think -filteredArrayUsingPredicate: might be better for you.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K = %#", #"firstName", #"Bob"];
NSArray *filteredArray = [array filteredArrayUsingPredicate:predicate];
This returns a sub-array of objects from the array that have the first name of "Bob".
I think your looking for -indexesOfObjectsPassingTest:
NSIndexSet *indexSet = [array indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
MyObject *myObject = (MyObject *)obj;
return [myObject.firstName isEqualToString:#"Bob"];
}];
This returns an index set of all the objects in the array with the first name of "Bob".
Another approach returning a new array containing only matching objects:
-(NSArray *)matchingClientsFromArray:(NSArray *)objects withFirstName:(NSString *)firstName andLastName:(NSString *)lastName{
NSMutableArray *objectArray = [NSMutableArray new];
for (Client *client in objectArray){
if ([client.firstName isEqualToString:firstName] &&
[client.lastName isEqualToString:lastName]) {
[objectArray addObject:client];
}
}
return [objectArray copy];
}