NSDictionary get property within list of objects - Objective C - ios

How would I get "Dog" from the following dictionary?
{
Id = "123";
Animal = [{
Id = "456";
Type = "Dog";
Sound = "Bark";
},
{
Id = "789";
Type = "Cat";
Sound = "Meow";
}]
}
I tried
NSString *firstAnimalType = dictionary[#"Animal"][#"Type"];
However since there are multiple animals, it can't recognize what I am trying to find. How would I get the first animal out of the list so that I can access its type? Thanks!

You can use some thing like this, first get animal object and if it exists then find its type from it
NSDictionary *firstAnimal = [dictionary[#"Animal"] firstObject];
if(firstAnimal) //in case your firstAnimal is Empty or it may be nil then may create any unwanted issues in further code so just check it first.
{
NSString *firstAnimalType = firstAnimal[#"Type"];
}

Enumeration method will help and you can stop when and where you want
[myDict[#"Animal"] enumerateObjectsUsingBlock:^(id _Nonnull objList, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(#"%#",objList[#"Type"]);
*stop = YES; //You can stop where you want
}];

You can simply access the first element of the array with castings and get its Type value.
NSString *firstAnimalType = ((NSDictionary *)[((NSArray *)dictionary[#"Animal"]) objectAtIndex: 0])[#"Type"];

for (NSDictionary *animal in dictionary[#"Animal"]) {
NSString *type = animal[#"Type"];
if ([type isKindOfClass:[NSString class]] && [type isEqualToString:#"Dog"]) {
// Dog found
}
}

Here you go:
NSArray *aryFinalAni = [dicMain valueForKey:#"Animal"];
NSArray *aryType = [aryFinalAni valueForKeyPath:#"Type"];
if([aryType containsObject:#"Dog"])
{
int indexOfDog = (int)[aryType indexOfObject:#"Dog"];
NSMutableDictionary *dicDog = [aryFinalAni objectAtIndex:indexOfDog];
NSLog(#"%#",dicDog);
}
else
{
NSLog(#"There is no Dog found.");
}

Try this code:
{
Id = "123";
Animal = [{
Id = "456";
Type = "Dog";
Sound = "Bark";
},
{
Id = "789";
Type = "Cat";
Sound = "Meow";
}]
}
1> NSArray *items = dictionary["Animal"];
2>
NSPredicate *predicate1 = [NSPredicate predicateWithFormat: #"Type CONTAINS[cd] %#", "Dog"];
NSArray *arrData = [items filteredArrayUsingPredicate:predicate1];
if arrData.count > 0 {
dictionary = [arrData objectAtIndex:0];
}
Result:
{
Id = "456";
Type = "Dog";
Sound = "Bark";
}

Related

Group element in NSMutableArray which contains object

I have an NSMutableArray that contains an object of a class model in each position like this.
The class model contains 2 types of information, which we will call id and name.
So, in every location of my NSMutableArray I have an object that contains 2 information.
Then, in the first position of my NSMutableArray I have
{
id = 1;
name = "Dan"; //this is the first object in NSMutableArray
}
In the second position of NSMutableArray, I have:
{
id = 1;
name = "Luca";
}
In the third position
{
id = 2;
name = "Tom";
}
and so on..
Ok, my goal is to make the union of identical IDs between the various objects within the SNMutableArray but it's too difficult!
For example, if I have:
{
id = 1;
name = "Tom";
}
{
id = 1;
name = "Luca";
}
{
id = 2;
name = "Steve";
}
{
id = 2;
name = "Jhon";
}
{
id = 3;
name = "Andrew";
}
The goal is:
{
id = 1;
name = "Tom";
name = "Luca";
}
{
id = 2;
name = "Steve";
name = "Jhon";
}
{
id = 3;
name = "Andrew";
}
Any ideas? would like to use this in the cellForRowAtIndexPath method and I tried to write this: (cm is my class model and myArray is the NSMutableArray which contains an object of cm class)
ClassModel *cm = [myArray objectAtIndex:indexPath.row];
NSMutableArray * resultArray = [NSMutableArray new];
NSArray * groups = [array valueForKeyPath:cm.ID];
for (NSString * groupId in groups)
{
     NSMutableDictionary * entry = [NSMutableDictionary new];
     [insert setObject: groupId forKey: # "groupId"];
     NSArray * groupNames = [array filteredArrayUsingPredicate: [NSPredicate predicateWithFormat: # "groupId =% #", groupId]];
     for (int i = 0; i <groupNames.count; i ++)
     {
         NSString * name = [[groupNames objectAtIndex: i] objectForKey: # "name"];
         [entry setObject: name forKey: [NSS string stringWithFormat: # "name% d", i + 1]];
     }
     [resultArray addObject: entry];
}
NSLog (# "% #", resultArray);
But this does not work..maybe because each element in my array is an object?? .. Help!
You have the right basic idea, but you shouldn't try and do this in cellForRowAt. Rather, you need to create a new array that has the data in the required structure and use that array as the source for your tableview. You will also need to create a new class to put in the array; one that has an id and an NSMutableArray for the names (I won't show this but I will call it GroupClassModel)
Use something like:
NSMutableDictionary *groups = [NSMutableDictionary new]
for (ClassModel *cm in array) {
GroupClassModel *gcm = groups[cm.id];
if (gcm == nil) {
gcm = [GroupClassModel new];
gcm.id = cm.id
groups[cm.id] = gcm
}
[gcm.names addObject:cm.name];
}
NSArray *groupedName = [groups allValues];
// Finally, sort groupedName by id if that is required.

Order NSArray with objects

I have an NSDictionary with the following data:
(lldb) po allFriends
{
71685207018702188 = {
id = 71685207018702188;
name = "mikeziri ";
username = mi;
};
93374822540641772 = {
id = 93374822540641772;
name = "Alan Weclipse";
username = zuka;
};
96553685978449395 = {
id = 96553685978449395;
name = "Monica Weclipse";
username = amonica;
};
96556113096345076 = {
id = 96556113096345076;
name = Xavier;
username = branko;
};
97017008427632119 = {
id = 97017008427632119;
name = "Dario Weclipse";
username = tarzan;
};
}
I'm sorting these objects based on the name, if they don't have a name, i will use the username. To do that, i create a new NSDictionary with the name and id and at the end of the method i sort them by name. The code to sort them is the following:
- (NSArray*)orderFriends
{
NSMutableDictionary* newFriendsDict = [[NSMutableDictionary alloc] init];
for (int i=0; i<[allFriends count];i++)
{
NSMutableDictionary* friendsDict = [[NSMutableDictionary alloc] init];
NSDictionary* friend = [allFriends objectForKey:[NSString stringWithFormat:#"%#", [sortedKeysFriends objectAtIndex:i]]];
if ([[friend objectForKey:#"name"] length] != 0)
{
[friendsDict setObject:[friend objectForKey:#"id"] forKey:#"id"];
[friendsDict setObject:[NSString stringWithFormat:#"%#", [friend objectForKey:#"name"]] forKey:#"name"];
}
else
{
[friendsDict setObject:[friend objectForKey:#"id"] forKey:#"id"];
[friendsDict setObject:[NSString stringWithFormat:#"%#", [friend objectForKey:#"username"]] forKey:#"name"];
}
[newFriendsDict setObject:friendsDict forKey:[NSNumber numberWithInt:i]];
}
NSArray* sp = nil;
sp = [[newFriendsDict allValues] sortedArrayUsingComparator:^(id obj1, id obj2){
NSString *one = [NSString stringWithFormat:#"%#", [obj1 objectForKey:#"name"]];
NSString *two = [NSString stringWithFormat:#"%#", [obj2 objectForKey:#"name"]];
return [one compare:two];
}];
return sp;
}
The problem is that the end result is wrong:
(lldb) po sp
<__NSArrayI 0x160491a0>(
{
id = 93374822540641772;
name = "Alan Weclipse";
},
{
id = 97017008427632119;
name = "Dario Weclipse";
},
{
id = 96553685978449395;
name = "Monica Weclipse";
},
{
id = 96556113096345076;
name = Xavier;
},
{
id = 71685207018702188;
name = "mikeziri ";
},
)
Case sensitive. make all string small or big.
You could also just change
return [one compare:two];
to
return [one compare:two options: options:NSCaseInsensitiveSearch];
Than it will be ordered alphabetically, no matter if upper or lower case...
Several things: There is no reason to build different dictionaries in order to sort, and good reason NOT to do so.
You already found the method sortedArrayUsingComparator. That takes a block that is used to compare pairs of objects, and returns a sorted array. You can use that method to implement any sorting criteria you want.
I would suggest writing a comparator block that compares the name properties of your objects unless it's blank, and uses username if that's blank. It would only be a few lines of code:
NSArray *sortedFriends = [[allFriends allValues] sortedArrayUsingComparator:
^(NSDictionary *obj1, NSDictionary *obj2)
{
NSString* key1 = obj1[#"name"] ? obj1[#"name"] : obj1[#"username"];
NSString* key2 = obj2[#"name"] ? obj2[#"name"] : obj2[#"username"];
return [key1 caseInsensitiveCompare: key2];
}];
EDIT: I just noticed (from your edit of my post) that you are starting from a dictionary, not an array. So what you want to do is to create a sorted array of all the values in the dictionary? Is it acceptable to discard the keys for all the items in your dictionary, and end up with a sorted array of the values?
The other thing you could do would be to build an array of the dictionary keys, sorted based on your sort criteria. Then you could use the array of keys to fetch the items from your dictionary in sorted order.

How to remove value from NSMutableArray

I have a NSMutableArray "coordinates" which gives me values like this
2014-01-11 09:52:15.479 DreamCloud[397:70b] (
{
1000 = {
Linecolor = 0X6495ED;
Lines = "4-s";
Xcord = "77.000000";
Xposition = "54.500000";
Ycord = "111.500000";
Yposition = "51.500000";
};
},
{
1001 = {
Linecolor = 0X6495ED;
Lines = "4-s";
Xcord = "45.000000";
Xposition = "42.500000";
Ycord = "417.000000";
Yposition = "54.000000";
};
},
{
1000 = {
Linecolor = 0X6495ED;
Lines = "4-s";
Xcord = "73.000000";
Xposition = "50.500000";
Ycord = "111.000000";
Yposition = "51.000000";
};
}
)
Within this I need ti remove the values for 1001 and recreate the array without 1001 . How do I do this.I am new in ios so I did not figure out how to do this .
for (NSMutableDictionary *deltag in deletelinearray)
{
NSMutableDictionary *gettagsdeleted = [deltag objectForKey:[NSString stringWithFormat:#"%d",myV.tag]];
NSLog(#"%#",gettagsdeleted);
int starttag=[gettagsdeleted objectForKey:#"Starttag"];
int endtag=[gettagsdeleted objectForKey:#"Endtag"];
}
NSLog(#"%#",coordinates);
Above is the code where in "coordinates " I get the array and start-tags and end-tags are 1000, 1001 . In coordinates I don't know the index as Kumar Kl said .
Consider your array name is coorditates
for (NSDictionary *dict in coorditates) {
if ([dict objectForKey:[NSString stringWithFormat:#"%d",1001]]) {
[coorditates removeObject:dict];
break;
}
}
You can also use NSPredicate but, for that coorditates array must be NSMutableArray
NSPredicate *pred = [NSPredicate predicateWithFormat:#"ANY self.#allKeys != %#", #"1001"];
[coorditates filterUsingPredicate:pred];
Try this for loop instead. Instead of selecting the object with the key it removes it.
for (NSMutableDictionary *deltag in deletelinearray)
{
[coordinates removeObjectForKey:[NSString stringWithFormat:#"%d",myV.tag]];
}
It is not a good coding practice to modify(insert or delete) the items in array while enumerating it. So first find your index and then delete it.
You don't need to create a new array, once the details with "1001" is removed. You already have an update array.
NSString *deleteKey=#"1001";
__block int deleteIndex=-1;
[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
for (NSString *key in [obj allKeys]) {
if([key isEqualToString:deleteKey]){
deleteIndex=idx;
*stop=YES;
}
}
}];
if(deleteIndex>=0){
[arr removeObjectAtIndex:deleteIndex];
}
You want to call the removeObjectAtIndex: function, but it appears your array contains dictionary objects and you want to remove the one with the key 1001. What you want to avoid is removing the object WHILE looping through the array.
So, what I would do is create a variable that will hold the index of the item once you find it, then loop through the array and once you find the object that it matches store the index and break. After, you shouldn't need to recreate the array after you remove the item, removing the object at the index you provide the above function will do just that for you. In your case, you'll want to do the following:
NSString *key = #"1001";
for (NSInteger index = 0; index < array.count; index++) {
NSDictionary *dictionary = coordinates[index];
if (dictionary[key]) {
indexToDelete = index;
break;
}
}
[coordinates removeObjectAtIndex:1001];
int i = 0;
for (NSDictionary *dict in coorditates)
{
if ([dict objectForKey:#"1001"])
{
[coorditates removeObjectAtIndex:i];
}
i++;
}

Get a value from nsdictionary

I want to give a key value from my NSDictionary and get the value associated to it.
I have this:
NSArray *plistContent = [NSArray arrayWithContentsOfURL:file];
NSLog(#"array::%#", plistContent);
dict = [plistContent objectAtIndex:indexPath.row];
cell.textLabel.text = [dict objectForKey:#"code"];
with plistContent :
(
{
code = world;
key = hello;
},
{
code = 456;
key = 123;
},
{
code = 1;
key = yes;
}
)
So how do I get "hello" by giving the dictionary "world"?
If I understand your question correctly, you want to locate the dictionary where "code" = "world" in order to get the value for "key".
If you want to keep the data structure as it is, then you will have to perform a sequential search, and one way to do that is simply:
NSString *keyValue = nil;
NSString *searchCode = #"world";
for (NSDictionary *dict in plistContents) {
if ([[dict objectForKey:#"code"] isEqualToString:searchCode]) {
keyValue = [dict objectForKey:#"key"]); // found it!
break;
}
}
However if you do alot of this searching then you are better off re-organizing the data structure so that it's a dictionary of dictionaries, keyed on the "code" value, converting it like this:
NSMutableDictionary *dictOfDicts = [[NSMutableDictionary alloc] init];
for (NSDictionary *dict in plistContents) {
[dictOfDicts setObject:dict
forKey:[dict objectForKey:#"code"]];
}
(note that code will break if one of the dictionaries doesn't contain the "code" entry).
And then look-up is as simple as:
NSDictionary *dict = [dictOfDicts objectForKey:#"world"]);
This will be "dead quick".
- (NSString*) findValueByCode:(NSString*) code inArray:(NSArray*) arr
{
for(NSDictonary* dict in arr)
{
if([[dict valueForKey:#"code"] isEqualToString:code])
{
return [dict valueForKey:#"key"]
}
}
return nil;
}

Getting index of an String value within an array of array

I have an unique scenario of getting index value of an element, where the structure is
Array - within Array - within Dictionary
(
{
STS = OPEN;
"STS_ICON" = "LIGHT_GREY";
},
"Headerquarter Planning"
),
(
{
STS = INPR;
"STS_ICON" = "LIGHT_BLUE";
},
"In Process"
),
(
{
STS = COMP;
"STS_ICON" = "LIGHT_GREEN";
},
Released
),
(
{
STS = CANC;
"STS_ICON" = "LIGHT_RED";
},
"ON HOLD - Call Transfer Delay"
)
)
iN THIS Case let's say i want index of #"ON HOLD - Call Transfer Delay" string.
I tried with like this..
NSUInteger index;
if([listOfStatus containsObject: list.statusType])
{
index = [listOfStatus indexOfObject: list.statusType];
}
where list.statusType is #"ON HOLD - Call Transfer Delay". But here i am getting "index" some weird value 15744929.
Try
- (NSInteger)findIndexOfStatus:(NSString *)status
{
NSString *filePath = [[NSBundle mainBundle]pathForResource:#"Status"
ofType:#"json"];
NSData *data = [[NSData alloc]initWithContentsOfFile:filePath];
NSArray *listOfStatus = [NSJSONSerialization JSONObjectWithData:data
options:0
error:nil];
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(NSArray *evaluatedObject, NSDictionary *bindings) {
//NSDictionary *dict = evaluatedObject[0];
//return [dict[#"STS"] isEqualToString:status];
NSString *statusType = evaluatedObject[1];
return [statusType isEqualToString:status];
}];
return [listOfStatus indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [predicate evaluateWithObject:obj];
}];
}
You can find the index by calling
NSInteger index = [self findIndexOfStatus:#"ON HOLD - Call Transfer Delay"];
I have also commented out an option to find out if you want to use the status code.
The Status.json file

Resources