how to filter only a specific key value from an array of dictionaries using NSPredicate - objective-c

NSArray *details = [NSArray arrayWithObjects:#"name",#"age",#"gender",nil];
NSArray *ray1 = #[#"ray",#"23",#"male"];
NSArray *steve1 = #[#"steve",#"23",#"male"];
NSDictionary *ray = [NSDictionary dictionaryWithObjects:ray1 forKeys:details];
NSDictionary *steve = [NSDictionary dictionaryWithObjects:steve1 forKeys:details];
NSArray *register = #[ray,steve];
i need to filter only the values of key using NSPredicate

this prints the values of the key "name" of all the dictionaries
NSArray *details = [NSArray arrayWithObjects:#"name",#"age",#"gender",nil];
NSArray *ray1 = #[#"ray",#"23",#"male"];
NSArray *steve1 = #[#"steve",#"23",#"male"];
NSDictionary *ray = [NSDictionary dictionaryWithObjects:ray1 forKeys:details];
NSDictionary *steve = [NSDictionary dictionaryWithObjects:steve1 forKeys:details];
NSArray *reg = #[ray,steve];
NSPredicate *pr = [NSPredicate predicateWithValue:YES];
NSArray *ar = [[reg valueForKey:#"name"] filteredArrayUsingPredicate:pr];
NSLog(#"%#",ar);

Related

Objective-C: Sort keys of NSDictionary based on dictionary entries

OK so I know that dictionaries can't be sorted. But, say I have NSMutableArray *keys = [someDictionary allKeys]; Now, I want to sort those keys, based on the corresponding values in the dictionary (alphabetically). So if the dictionary contains key=someString, then I want to sort keys based on the strings they correspond to. I think its some application of sortUsingComparator but its a little out of my reach at this point.
NSArray *keys = [someDictionary allKeys];
NSArray *sortedKeys = [keys sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSString *first = [someDictionary objectForKey:a];
NSString *second = [someDictionary objectForKey:b];
return [first compare:second];
}];
NSDictionary *dict = // however you obtain the dictionary
NSMutableArray *sortedKeys = [NSMutableArray array];
NSArray *objs = [dict allValues];
NSArray *sortedObjs = [objs sortedArrayUsingSelector:#selector(compare:)];
for (NSString *s in sortedObjs)
[sortedKeys addObjectsFromArray:[dict allKeysForObject:s]];
Now sortedKey will contain the keys sorted by their corresponding objects.
Sort keys of NSDictionary based on dictionary keys
Abobe is for returning a sorted array with based on dictionary content, this is for returning an array sorted by dictionary key:
NSArray *keys = [theDictionary allKeys];
NSArray *sortedKeys = [keys sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
return [a compare:b];
}];
NSMutableArray *sortedValues = [NSMutableArray new];
for(NSString *key in sortedKeys)
[sortedValues addObject:[dictFilterValues objectForKey:key]];
Just write it here cause I didn't find it anywhere: To get an alphanumeric sorted NSDictionary back from an NSDictionary based on the value - which in my case was neccessary - you can do the following:
//sort typeDict alphanumeric to show it in order of values
NSArray *keys = [typeDict allKeys];
NSArray *sortedKeys = [keys sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSString *first = [typeDict objectForKey:a];
NSString *second = [typeDict objectForKey:b];
return [first compare:second];
}];
NSLog(#"sorted Array: %#", sortedKeys);
NSMutableDictionary *sortedTypeDict = [NSMutableDictionary dictionary];
int counter = 0;
for(int i=0; i < [typeDict count]; i++){
NSString *val = [typeDict objectForKey:[sortedKeys objectAtIndex:counter]];
NSString *thekey = [sortedKeys objectAtIndex:counter];
[sortedTypeDict setObject:val forKey:thekey];
counter++;
}
NSLog(#"\n\nsorted dict: %#", sortedTypeDict);
Not a big deal!
If any value from the dictionary is null then use this code
NSArray *keys = [typeDict allKeys];
NSSortDescriptor *sd = [[NSSortDescriptor alloc] initWithKey:nil ascending:YES];
NSArray *sortedKeys = [keys sortedArrayUsingDescriptors:#[sd]];
NSLog(#"SORT 1 %#",sortedKeys);
NSMutableDictionary *sortedTypeDict = [NSMutableDictionary dictionary];
int counter = 0;
for(int i=0; i < [typeDict count]; i++){
id val = [typeDict objectForKey:[sortedKeys objectAtIndex:counter]];
NSString *thekey = [sortedKeys objectAtIndex:counter];
[sortedTypeDict setObject:val forKey:thekey];
counter++;
}
NSLog(#"\n\nsorted dict: %#", sortedTypeDict);

NSPredicate 'OR' filtering based on an NSArray of keys

Consider the following NSArray:
NSArray *dataSet = [[NSArray alloc] initWithObjects:
[NSDictionary dictionaryWithObjectsAndKeys:#"abc", #"key1", #"def", #"key2", #"hij", #"key3", nil],
[NSDictionary dictionaryWithObjectsAndKeys:#"klm", #"key1", #"nop", #"key2", nil],
[NSDictionary dictionaryWithObjectsAndKeys:#"qrs", #"key2", #"tuv", #"key4", nil],
[NSDictionary dictionaryWithObjectsAndKeys:#"wxy", #"key3", nil],
nil];
I am able to filter this array to find dictionary objects that contain the key key1
// Filter our dataSet to only contain dictionary objects with a key of 'key1'
NSString *key = #"key1";
NSPredicate *key1Predicate = [NSPredicate predicateWithFormat:#"%# IN self.#allKeys", key];
NSArray *filteretSet1 = [dataSet filteredArrayUsingPredicate:key1Predicate];
NSLog(#"filteretSet1: %#",filteretSet1);
Which appropriately returns:
filteretSet1: (
{
key1 = abc;
key2 = def;
key3 = hij;
},
{
key1 = klm;
key2 = nop;
}
)
Now, I am wanting to filter the dataSet for dictionary objects containing ANY of the keys in an NSArray.
For example, using the array: NSArray *keySet = [NSArray arrayWithObjects:#"key1", #"key3", nil]; I want to create a predicate that returns and array of any dictionary objects that contain either 'key1' or 'key3' (ie. in this example all dictionary objects would be returned except for the third object - as it does not contain either 'key1' or 'key3').
Any ideas on how I would achieve this? Would I have to use a compound predicate?
The ANY operator of NSPredicate covers this:
NSSet *keys = [NSSet setWithObjects:#"key1", #"key3", nil];
NSPredicate *key1Predicate = [NSPredicate predicateWithFormat:#"any self.#allKeys in %#", keys];
Do this:
NSString *key = #"key1";
NSString *key1 = #"key3";
NSPredicate *key1Predicate = [NSPredicate predicateWithFormat:#"%# IN self.#allKeys OR %# IN self.#allKeys",key,key1];
NSArray *filteretSet1 = [dataSet filteredArrayUsingPredicate:key1Predicate];
NSLog(#"filteretSet1: %#",filteretSet1);
Works perfectly for me. Hope Helpful
Altough the question has been answered, you could also use block for more granularity:
NSArray *filter = [NSArray arrayWithObjects:#"key1", #"key3",nil];
NSPredicate *filterBlock = [NSPredicate predicateWithBlock: ^BOOL(id obj, NSDictionary *bind){
NSDictionary *data = (NSDictionary*)obj;
// use 'filter' and implement your logic and return YES or NO
}];
[dataSet filteredArrayUsingPredicate:filterBlock];
That could be rearranged as you want, maybe within its own method.

Filter NSArray with 2D-NSDictionaries using NSPredicate

i have a NSArray containing some NSDictionaries which themselves also include a NSDictionary.
NSDictionary *dict1 = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:#"cover" forKey:#"type"] forKey:#"image"];
NSDictionary *dict2 = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:#"cover" forKey:#"type"] forKey:#"image"];
NSDictionary *dict3 = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:#"back" forKey:#"type"] forKey:#"image"];
NSDictionary *dict4 = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:#"cover" forKey:#"type"] forKey:#"image"];
NSArray *myArray = [NSArray arrayWithObjects:dict1, dict2, dict3, dict4, nil];
is there a way to filter myArray for all Image-Dictionaries where the type is f.e. "cover" using a NSPredicate?
tried predicates like
predicateWithFormat:#"(SELF.image.type == %#)", #"cover"]
or
predicateWithFormat:#"(image.type == %#)", #"cover"]
but without success.
thanks in advance! leave a comment if something is unclear
// edit
so
NSPredicate *p = [NSPredicate predicateWithFormat:#"image.type == %#", #"cover"];
is working. but in my case i want to sort out size == original. what i did is
NSPredicate *p = [NSPredicate predicateWithFormat:#"image.size == %#", #"original"];
but then my app crashes with
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSSymbolicExpression length]: unrecognized selector sent to instance
and pointing to my filteredArrayUsingPredicate method. i cannot see any difference between type and size. see my NSLog of my Array here
(
{
image = {
height = 1500;
id = 4e5808765e73d607350059b4;
size = original;
type = poster;
url = "someurl";
width = 1000;
};
},
{
image = {
height = 750;
id = 4e5808765e73d607350059b4;
size = mid;
type = poster;
url = "someurl";
width = 500;
};
},
anybody knows why it crashes when i try to use size instead of type ?
SIZE is a reserved keyword.
Found at the bottom of the Predicate Programming Guide:
The following words are reserved:
AND, OR, IN, NOT, ALL, ANY, SOME, NONE, LIKE, CASEINSENSITIVE, CI, MATCHES, CONTAINS, BEGINSWITH, ENDSWITH, BETWEEN, NULL, NIL, SELF, TRUE, YES, FALSE, NO, FIRST, LAST, SIZE, ANYKEY, SUBQUERY, CAST, TRUEPREDICATE, FALSEPREDICATE
The following code worked for me:
NSDictionary *dict1 = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:#"cover" forKey:#"type"] forKey:#"image"];
NSDictionary *dict2 = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:#"cover" forKey:#"type"] forKey:#"image"];
NSDictionary *dict3 = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:#"back" forKey:#"type"] forKey:#"image"];
NSDictionary *dict4 = [NSDictionary dictionaryWithObject:[NSDictionary dictionaryWithObject:#"cover" forKey:#"type"] forKey:#"image"];
NSArray *myArray = [NSArray arrayWithObjects:dict1, dict2, dict3, dict4, nil];
NSPredicate *p = [NSPredicate predicateWithFormat:#"image.type == %#", #"cover"];
NSLog(#"%#", [myArray filteredArrayUsingPredicate:p]);

How can I retrieve all the contents of an NSDictionary?

I want to select and retrieve all the contents from an NSDictionary. I have a structure like this
- (void)viewDidLoad {
[super viewDidLoad];
listaOggetti = [[NSMutableArray alloc] init];
NSArray *arrayOne = [NSArray arrayWithObjects: #"First",#"Second",#"Third", nil];
NSArray *sortedOne = [arrayOne sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSDictionary *dictOne = [NSDictionary dictionaryWithObject:sortedOne forKey:#"Elementi"];
NSArray *arrayTWo = [NSArray arrayWithObjects:#"First1",#"Second1" ..., nil];
NSArray *sortedTwo = [arrayTwo sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSDictionary *dictTwo = [NSDictionary dictionaryWithObject:sortedTWo forKey:#"Elementi"];
NSArray *arrayThree = [NSArray arrayWithObjects:#"First2",#"Second2" ... , nil];
NSArray *sortedThree = [arrayThree sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSDictionary *dictThree = [NSDictionary dictionaryWithObject:sortedThree forKey:#"Elementi"];
[listaOggetti addObject:dictOne];
[listaOggetti addObject:dictTwo];
[listaOggetti addObject:dictThree];
}
And I want to retrieve all the objects for the key #"Elementi" (should be around 45) in order to add them in another array, like:
NSDictionary *dict = [listaOggetti objectAtIndex:indexPath.section];
NSArray *array = [dict objectForKey:#"Elementi"];
cellValue = [array objectAtIndex:indexPath.row] ;
(With this, dict is only 9 objects filled in my project).
At the end, the *array should be around 45 objects filled. I tried with allValues, but didn't work.
How can I fix it?
The easiest is to do this in -viewDidLoad:
NSMutableArray *allObjects = [[NSMutableArray alloc] init];
[allObjects addObjectsFromArray:sortedOne];
[allObjects addObjectsFromArray:sortedTwo];
[allObjects addObjectsFromArray:sortedThree];
Alternately, you can get them from the dictionaries in a similar fashion:
NSMutableArray *allObjects = [[NSMutableArray alloc] init];
[allObjects addObjectsFromArray:[[listaOggetti objectAtIndex:0] objectForKey#"Elementi"];
[allObjects addObjectsFromArray:[[listaOggetti objectAtIndex:1] objectForKey#"Elementi"];
[allObjects addObjectsFromArray:[[listaOggetti objectAtIndex:2] objectForKey#"Elementi"];
What you are failing to understand is that listaOggetti is an NSMutableArray containing three objects. When you call
NSDictionary *dict = [listaOggetti objectAtIndex:indexPath.section];
the result is that dict is a single dictionary, one of the three objects in listaOggetti. Therefore when you call
NSArray *array = [dict objectForKey:#"Elementi"];
the result is that array is the object for the key #"Elementi" of that one single dictionary dict. Your code makes no attempt to combine the three DIFFERENT dictionaries or to combine the three arrays, each set as objectForKey:#"Elementi" for the three DIFFERENT dictionaries.
If you want one array that is the concatenation of all three different arrays, then use one of the snippets provided above. In both of these snippets, the result is that allObjects is an NSMutableArray containing all three arrays, in order.

How do you change the elements within an NSArray?

I am a bit confused as to how arrays are handled in Objective-C.
If I have an array such as
NSarray *myArray = [[NSArray alloc]
initWithObjects:#"N", #"N", #"N", #"N", #"N",
nil];
how do I change the first occurrence to "Y"?
You need an NSMutableArray ..
NSMutableArray *myArray = [[NSMutableArray alloc]
initWithObjects:#"N", #"N", #"N", #"N", #"N",
nil];
and then
[myArray replaceObjectAtIndex:0 withObject:#"Y"];
You can't, because NSArray is immutable. But if you use NSMutableArray instead, then you can. See replaceObjectAtIndex:withObject::
[myArray replaceObjectAtIndex:0 withObject:#"Y"]
Write a helper method
-(NSArray *)replaceObjectAtIndex:(int)index inArray:(NSArray *)array withObject:(id)object {
NSMutableArray *mutableArray = [array mutableCopy];
mutableArray[index] = object;
return [NSArray arrayWithArray:mutableArray];
}
Now you can test this method with
NSArray *arr = #[#"a", #"b", #"c"];
arr = [self replaceObjectAtIndex:1 inArray:arr withObject:#"d"];
logObject(arr);
This outputs
arr = (
a,
d,
c
)
You can use similar method for NSDictionary
-(NSDictionary *)replaceObjectWithKey:(id)key inDictionary:(NSDictionary *)dict withObject:(id)object {
NSMutableDictionary *mutableDict = [dict mutableCopy];
mutableDict[key] = object;
return [NSDictionary dictionaryWithDictionary:mutableDict];
}
You can test it with
NSDictionary *dict = #{#"name": #"Albert", #"salary": #3500};
dict = [self replaceObjectWithKey:#"salary" inDictionary:dict withObject:#4400];
logObject(dict);
which outputs
dict = {
name = Albert;
salary = 4400;
}
You could even add this as a category and have it easily available.