search element in NSDictionary nested in another NSDictionary - ios

Background:
a Object:
MyObject : NSObject
#property NSInteger type;
a NSDictionary:
#{
#"1":#{#"1":MyObject}
#"2":#{#"1":MyObject}
}
Now,got a MyObject and it's type=1;
how to make sure whether this MyObject contained in the NSDictionary?

I'm taking into consideration, that your dictionary only has one key/pair and there are no similar key names present
NSDictionary *dict = #{ #"a":#{#"c":#"MyObject"} ,#"b":#{#"d":#"MyObject"} } ;
NSMutableArray *valuesArray = [[NSMutableArray alloc]init];
// enumerate and add all values to our value array
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSLog(#"Your value : %#", [obj description]);
[valuesArray addObject:[[obj allValues] firstObject]];
}];
// check whether this value is present
if ([valuesArray containsObject:#"MyObject"]) {
NSLog(#"My Object found",);
}

Related

Remove entries from NSMutableDictionary based on match on NSString value

After a network call to the Instagram API, I get back a responseDictionary NSDictionary delegate with the following Key/Value structure:
{
data = (
{
bio = "Los Angeles/Orange County Realtor\U00ae \n\U6d1b\U6749\U77f6\U623f\U5730\U4ea7\U7ecf\U7eaa\U4eba\nCall/Text/WhatsApp: (310) 717-1321\nEmail: Jxxxcom\nWeChat (\U5fae\U4fe1): xx";
"full_name" = "xx yy (\U7530\U4f73\U6dfc) Rx Realty";
id = 25354408;
"profile_picture" = "http://scontent-a.cdninstagram.com/hphotos-xpa1/outbound-distillery/t0.0-20/OBPTH/profiles/profile_xxx_75sq_1391378894.jpg";
username = jxxi;
website = "http://www.Jxghty.com";
},
The profile_picture key often has an NSString value that contains anonymousUser (for the users who didn't set any profile pictures).
I am looking to remove those entries from my responseDictionary as follows:
//Create mutable copy of IG responseDictionary
NSMutableDictionary *dictCleanAvatars = [responseDictionary mutableCopy];
NSLog(#"Log dictCleanAvatars after mutableCopy IG response: %#", dictCleanAvatars);
NSArray *keys = [dictCleanAvatars allKeys]; //get all the keys
NSUInteger k2 = [dictCleanAvatars count];
NSLog(#"k2 in dictCleanAvatars before cleanup is: %lu", (unsigned long)k2);
for (int i = 0; i<k2; i++)
{
if ([[dictCleanAvatars objectForKey:[keys objectAtIndex:i]] isKindOfClass:[NSString class]])
{
//if its an NSString - don't want an exception if its another type of object
NSLog(#"Yes, objectAtIndex:i us Kind ofClass NSString for i = %d", i);
if ([[dictCleanAvatars objectForKey:[keys objectAtIndex:i]] rangeOfString:#"anonymousUser"].location != NSNotFound)
{
NSLog(#"Yes, anonymousUser identified in objectAtIndex:i for i = %d", i);
//if object has the key word im looking for
[dictCleanAvatars removeObjectForKey:[keys objectAtIndex:i]]; //remove the key
NSLog(#"That's dictCleanAvatars after loop %d: %#", i, dictCleanAvatars);
}
}
}
But this doesn't work.
Would value feedback from more experience iOS developers.
If you're trying to build an array that includes everything from the data key's array, but omitting those dictionaries for which profile_picture contains the string "AnonymousUser", you can use NSPredicate:
NSArray *dataArray = responseDictionary[#"data"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"not (profile_picture contains 'AnonymousUser')"];
NSArray *filteredArray = [dataArray filteredArrayUsingPredicate:predicate];
Or you can use predicateWithBlock:
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(NSDictionary *evaluatedObject, NSDictionary *bindings) {
return [evaluatedObject[#"profile_picture"] rangeOfString:#"AnonymousUser"].location == NSNotFound;
}];
BTW, if you already have a mutable array, you can also remove entries from it using filterUsingPredicate, using the above predicates:
NSMutableArray *mutableDataArray = [responseDictionary[#"data"] mutableCopy];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"not (profile_picture contains 'AnonymousUser')"];
[mutableDataArray filterUsingPredicate:predicate];
If, on the other hand, you don't want to remove entire dictionaries from the array of dictionaries, but rather want to simply remove the occurrences of profile_picture for which "AnonymousUser" is present, you want to ensure that not only is the array mutable, but so are its constituent dictionaries.
The easiest way of doing this is to specify the NSJSONReadingMutableContainers option when parsing the JSON. Then you can just iterate through the NSMutableDictionary entries, removing the profile_picture entries with a profile_picture with "AnonymousUser" in them:
NSMutableDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&error];
NSMutableArray *mutableDataArray = responseDictionary[#"data"];
for (NSMutableDictionary *dictionary in mutableDataArray) {
NSString *profilePicture = dictionary[#"profile_picture"];
if ([profilePicture rangeOfString:#"AnonymousUser"].location != NSNotFound) {
[dictionary removeObjectForKey:#"profile_picture"];
}
}
If, however, you can't specify the NSJSONReadingMutableContainers option when you parse the JSON and are stuck with a immutable collection, you need to make a mutable copy of it. Unfortunately, a simple mutableCopy of the array won't make the member dictionaries mutable themselves, but you can use a Core Foundation call to CFPropertyListCreateDeepCopy to make a mutable array with mutable entries, which you can then modify:
NSMutableArray *mutableDataArray = CFBridgingRelease(CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFArrayRef)responseDictionary[#"data"], kCFPropertyListMutableContainers));
Then you can use the above for loop, iterating through this array's dictionary entries, removing the offending profile_picture entries.
if [[dictCleanAvatars objectForKey:[keys objectAtIndex:i]] isEqualToString#"anonymousUser"] {
The problem is, suppose [dictCleanAvatars objectForKey:[keys objectAtIndex:i]] is not an NSString? You might want to check for that first.
If the only field you are looking at is profile_picture, I would go with a less generic approach which is much more readable and understandable
This code works for me
- (void)testExample
{
NSDictionary *dictionary = #{ #"data": #[ #{ #"bio": #"blah blah", #"profile_picture": #"some stuff anonymousUser other stuff" },
#{ #"bio": #"some other object", #"profile_picture": #"some other profile picture link" }] };
// dictionary is a mock of the data you provided
NSArray *data = [dictionary objectForKey:#"data"];
for (NSDictionary * avatarDict in data) {
NSMutableDictionary *mdict = [avatarDict mutableCopy];
id ppid = [mdict objectForKey:#"profile_picture"];
if ([ppid isKindOfClass:[NSString class]]) {
NSString *pp = (NSString *)ppid;
if ([pp rangeOfString:#"anonymousUser"].location != NSNotFound) {
[mdict removeObjectForKey:#"profile_picture"];
}
}
NSLog(#"altered dictionary: %#", mdict);
}
}
Output:
2014-08-13 10:53:36.727 test[11981:60b] altered dictionary: {
bio = "blah blah";
}
2014-08-13 10:53:36.728 test[11981:60b] altered dictionary: {
bio = "some other object";
"profile_picture" = "some other profile picture link";
}

Projection of properties of objects in NSArray/NSSet collections

I have an array of objects that I convert to a NSSet:
NSArray *arr = #[#{ #"someProp": #21, #"unnecessaryProp": #"tada" }, ... ];
NSSet *collection = [NSSet setWithArray:arr];
I would like to project the properties I want (by key) out of each object in the set and end up with a new array like:
NSArray *projectedArray = [collection allObjects]; // #[#{ "someProp": #21 }, ... ], "unnecessaryProp" has been removed
Besides enumeration, is there any other way, perhaps NSPredicate?
NOTE: The objects in the array are subclasses of NSObject, in my example I mentioned a NSDictionary
Since NSPredicate does not do projections, you would end up enumerating the set. I would enumerate it with a block, and project the keys in the individual dictionaries like this:
NSArray *keep= #["someProp"];
NSMutableArray *res = [NSMutableArray array];
[collection enumerateObjectsUsingBlock:^(id dict, BOOL *stop) {
NSArray *values = [dict objectsForKeys:keep notFoundMarker:#""];
[res addObject:[NSDictionary dictionaryWithObjects:values forKeys:keep]];
}];
EDIT : (in response to comments)
I should have mentioned that the objects inside the array are subclasses of NSObject and objectsForKeys is not a method.
Then you could use MartinR's suggestion to build a dictionary using KVC:
NSArray *keep= #["someProp"];
NSMutableArray *res = [NSMutableArray array];
[collection enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
[res addObject:[obj dictionaryWithValuesForKeys:keep]];
}];
If you only need the values for one property of the objects in a collection of type NSSet or NSArray or their subclasses, you can use the KVC method valueForKey:
NSArray *dogs = #[#{#"name" : #"Fido",
#"toys" : #[#"Ball", #"Kong"]},
#{#"name" : #"Rover",
#"toys" : #[#"Ball", #"Rope"]},
#{#"name" : #"Spot",
#"toys" : #[#"Rope", #"Kong"]}];
NSArray *vals = [set valueForKey:#"name"];
NSLog(#"%#", vals);
The above code prints the following on the console:
2014-05-16 09:26:58.293 xctest[17223:303] (
Fido,
Rover,
Spot
)
If you need the values of several properties of the objects in the collection, use dictionaryWithValuesForKeys:. Given the same array as in the previous example, the following code...
NSDictionary *dict = [dogs dictionaryWithValuesForKeys:#[#"name", #"toys"]];
NSLog(#"%#", dict);
produces an array of dictionaries, and logs the following output:
2014-05-16 09:35:34.793 xctest[17275:303] {
name = (
Fido,
Rover,
Spot
);
toys = (
(
Ball,
Kong
),
(
Ball,
Rope
),
(
Rope,
Kong
)
);
}
This works regardless of whether the objects in the target collections are instances of NSDictionary or of custom classes.
you can use indexOfObjectPassingTest on your array or NSSet.
__block NSUInteger maxIdex = [_myArrray count]-1;
__block NSMutableIndexSet* objToRemove = [[NSMutableIndexSet alloc]init];
[_myArrray indexOfObjectPassingTest:^(id object, NSUInteger idx, BOOL * stop){
MyObject *obj = (MyObject*)object;
if(....){
[objToRemove addIndex:[_myArrray indexOfObject:obj]];
}
*stop = (idx == maxIdex);
return *stop;
}];
[_myArrray removeObjectsAtIndexes:objToRemove];

Assign NSNull Object to NSString

I'm writing an iOS App where i need to get data from a SQL-Database over mobile Services from Azure.
After downloading the data I get a NSDictionary with all attributes from the SQL-Table. If an attribute is empty, the value is NSNull.
Is there a way to pass NSNull to NSString without an IF-Statement (I don't want to have 20 if statements..)?
I wrote a category just for dealing with this issue. I used it with Core Data but it should help you, too.
#interface NSDictionary (Extensions)
- (id)NSNullToNilForKey:(NSString *)key;
#end
#implementation NSDictionary (Extensions)
- (id)NSNullToNilForKey:(NSString *)key
{
id value = [self valueForKey:key];
return value != [NSNull null] ? value : nil;
}
#end
Sample use:
NSString *value = [dictionary NSNullToNilForKey:#"key"];
You can't just assign it, but you can filter out all of the NSNull instances using something like this:
NSDictionary *dictionary = // data from server
NSDictionary *filteredDictionary = [dictionary mutableCopy];
NSSet *keysToRemove = [orig keysOfEntriesPassingTest:^BOOL(id key, id obj, BOOL *stop) {
if (obj == [NSNull null]) {
return YES;
} else {
return NO;
}
}];
[filteredDictionary removeObjectsForKeys:[keysToRemove allObjects]];
Now you have the same dictionary except that every key with an NSNull has been removed.

Search element in nsdictionary by value

I have nsdictionary which contains elements with following structure
name --> value
email--> key
I get value(of above structure) from user,
now I want to search element in nsdictionary by value(entered by user) not by key, whether it is present in nsdictionary or not and also want to get index of that element if present.
How to do this?
The best to do so would propably be
- (NSArray *)allKeysForObject:(id)anObject
This method of NSDictionary gives you back all the keys having anObject as their value. If you only have each object once in the whole dictionary it will logically return an array with only one key in it.
NSArray * users = ...; //your array of NSDictionary objects
NSPredicate *filter = [NSPredicate predicateWithFormat:#"email = test#gmail.com"];
NSArray *filteredContacts = [contacts filteredArrayUsingPredicate:filter];
for more than one value of email, then use an OR in the predicate:
filter = [NSPredicate predicateWithFormat:#"contact_type = 42 OR contact_type = 23"];
The dictionary data structure has no 'order', so you'd have to search for your key by iterating the collection and looking for the desired value.
Example:
NSString *targetKey = nil;
NSArray *allKeys = [collection allKeys];
for (int i = 0; i < [allKeys count]; ++i) {
NSString *key = [allKeys objectAtIndex:i];
NSString *obj = [collection objectForKey:key];
if ([obj isEqualToString:searchedString]) { // searchedString is what you're looking for
targetKey = key;
break;
}
}
// check if key was found (not nil) & proceed
// ...
You can search the entered value in NSDictionary , but you can't get an index of value , as NSDictionary has no order of key value pair.
NSArray *array = [yourDictionaryObject allValues];
if ([array containsObject:#"userEnteredValue"]) {
<#statements#>
}
You need to iterate through the Dictionary for the keys has the Value of your need:
Try this:
NSArray *keys= [json allKeys];
for (NSString *keysV in keys){
NSLog(#"Keys are %#", keysV);
if([Your_Dict objectForKey: keysV] isEqual:#"string to Match"){
//Do your stuff here
}
}

How to loop NSDictionary obtained from JSON?

How can i loop through the following dictionary obtained from JSON? How can i loop to get only the id 0001, 0002?
{
0001 = {
userName = "a";
photo = "";
};
0002 = {
userName = "b";
photo = "";
};
}
You loop thru the NSDictionary keys:
NSArray *keys = [dictionary allKey];
for (id *key in keys ) {
NSDictionary *userPhoto = [dictionary objectForKey:key];
// here you can either parse the object to a custom class
// or just add it to an array.
}
Or use the fast enumeration directly on the NSDictionary:
for (id *key in dictionary ) {
NSDictionary *userPhoto = [dictionary objectForKey:key];
// here you can either parse the object to a custom class
// or just add it to an array.
}
Per key you can retrieve the object.
or use the enumerateKeysAndObjectsUsingBlock:
[dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
// Here you can access the object and key directly.
}
Try this way...
Get all keys
NSArray *a=[yourDictionary allKeys];
NSArray *keys = [dictionary allKeys];
Try this. You will get all keys in an array. And then you can get them in NSString accordingly .
Another alternative is using the enumerateKeysAndObjectsUsingBlock: api to enumerate the keys and objects,
Usage is pretty simple,
[dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSLog(#"Key: %#, Value:%#",key,obj);
if([key isEqualToString:#"0001"]) {
//Do something
}
// etc.
}];
Hope that helps!
I found the answer. I already tried with the following code but it is giving all the data.
Because the json i got is in the worng format.
for (NSString *key in Dict) {}

Resources