Iterate through two layers of NSDictionary - ios

I am trying to iterate through an NSDictionary from a serialized JSON file. The dictionary has two levels and I cannot seem to access the second layer properly.
I am wondering if there is a way to increment an objectForKey such as:
for (id key in [itemList allKeys]) {
[objectivesArray addObject:[[itemList objectForKey:#"Example0"] objectForKey:#"Objective"]];
}
My keys in the Dictionary (second level) are like, Example0, Example1, Example2.
UPDATE:
The desired output would be arrays for each of the values contained within the top level keys. The JSON basically looks like this:
Top Level
Example1
Key1: Value1
Key2: Value2
Example2
Key1: Value1
Key2: Value2
and so on. I have tried nesting For loops to get the Key and values:
for (id key in [itemList allKeys]) {
id value = [itemList objectForKey:key];
Value = [value objectForKey:#"Example1"];
firstLevelDictionary = [itemList objectForKey:key];
for (id key2 in firstLevelDictionary) {
NSLog(#"%#", [firstLevelDictionary objectForKey:#"Key1"]);
[keyArray addObject:[firstLevelDictionary objectForKey:#"Key1"]];
}
}
etc.
Now, I can access them when I manually write them all out:
[key1Array addObject:[[itemList objectForKey:#"Key1"] objectForKey:#"Value1"]];
[key2Array addObject:[[itemList objectForKey:#"Key2"] objectForKey:#"Value2"]];
But that is obviously not at all what I want. So I'm wondering if there's a way to do nested loops by incrementing an integer contained within the objectForKey key value.
UPDATE 2: this is the JSON format Im working with, I put baseball terms in place of data for now:
{
"Situ0":{
"Situation":"Tying Runner on 1st",
"Bases":[
1
],
"Outs":0,
"Score":[
1,
2
],
"Purpose":"Sac Bunt",
"Objective":"Bunt"
},
"Situ1":{
"Situation":"Tying Runner On 2nd",
"Bases":[
2
],
"Outs":1,
"Score":[
1,
2
],
"Purpose":"Score / Move Runner Over",
"Objective":"Hit Behind Runner / Hit"
}

This can help you to iterate the second layer of NSDictionary:
- (void)iterateSecondLayerOfDictionary:(NSDictionary *)dict {
for (id subDictKey in dict.allKeys) {
NSDictionary *subDict = [dict objectForKey:subDictKey];
for (id valueKey in subDict.allKeys) {
NSString *value = [subDict objectForKey:valueKey];
NSLog(#"%#", value);
}
}
}
To test, here is some example data:
NSDictionary *subDict = #{ #"key1": #"value1",
#"key2": #"value2",
#"key3": #"value3",
#"key4": #"value4"
};
NSDictionary *dict = #{ #"Example0": subDict,
#"Example1": subDict,
#"Example2": subDict
};
NSLog(#"%#", dict);
[self iterateSecondLayerOfDictionary:dict];
Output:
//This is your actual data
{
Example0 = {
key1 = value1;
key2 = value2;
key3 = value3;
key4 = value4;
};
Example1 = {
key1 = value1;
key2 = value2;
key3 = value3;
key4 = value4;
};
Example2 = {
key1 = value1;
key2 = value2;
key3 = value3;
key4 = value4;
};
}
//These are the values you are trying to access. Though the orders aren't guaranteed as they are NSDictionaries
value3
value2
value1
value4
value3
value4
value2
value1
value3
value2
value1
value4

I think this is what you need. But I highly recommend don't follow this method.
Tip: Instead of keeping subDict in another dictionary try to get it inside an Array (from api). Then you can easily get it by NSArray * key1Array = [array valueForKey:#"key1"];
NSDictionary *subDict = #{ #"key0": #"value0",
#"key1": #"value1",
#"key2": #"value2",
};
NSDictionary *dict = #{ #"Example0": subDict,
#"Example1": subDict,
#"Example2": subDict
};
NSMutableDictionary *keyValues = [NSMutableDictionary new];
for (int i =0; i < dict.count; i ++) {
NSString *key = [NSString stringWithFormat:#"Example%d",i];
NSDictionary *innerDic = [dict valueForKey:key];
NSMutableArray *array = [NSMutableArray new];
NSString *innerKey ;
for (int j = 0; j < innerDic.count; j ++) {
innerKey = [NSString stringWithFormat:#"key%d",i];
NSString *value = [innerDic valueForKey:innerKey];
[array addObject:value];
}
[keyValues setObject:array forKey:innerKey];
}
NSLog(#"KEY VALUES: %#", keyValues);
By this you can get key1Array by
key1Array = [keyValues valueForKey: #"key1"];

Related

how to get nsDictionary element by using for-in

NSDictionary *myDict = #{#"one":#"1",#"two":#"2"};
for (NSDictionary* tmp in myDict) {
NSLog(#"%#",tmp);
}
resut:
my tmpis NSString
I want to get a dictionary with key= one , value = 1
for in for NSDictionary will iterate the keys.
for (NSString * key in myDict) {
NSLog(#"%#",key);
NSString * value = [myDict objectForKey:key];
}
If you want to get a dictionary. You have to create a dictionary from these values
for (NSString * key in myDict) {
NSLog(#"%#",key);
NSString * value = [myDict objectForKey:key];
NSDictionary * dict = #{key:value};
}
Or you should init like this:
NSArray *arrDict = #[{#{"one":#"1"},#{#"two":#"2"}];
for (NSDictionary* tmp in arrDict) {
NSLog(#"%#",tmp);
}
You can get all keys from your dic then add the key and value to your new dic like this:
NSDictionary *myDict = #{#"one":#"1",#"two":#"2"};
NSArray *keys = [myDict allKeys];
for (NSString *key in keys) {
NSDictionary *yourDic = #{key: [myDict valueForKey:key]};
NSLog(#"%#", yourDic);
}
You didn't create it that way. If you wanted to have a NSDictionary inside another NSDictionary you should write something like this :
NSDictionary *myDict = #{
#"firstDict" : #{
#"one":#"1"
},
#"secondDict": #{
#"two":#"2"
}
};
Above code will create a NSDictionary with two dictionaries at keys #firstDict and #secondDict.
Also, bear in mind, that because dictionaries are key-value pairs, using a for-in loop, actually loops through the keys in that dictionary. So your code is equivalent to:
for(NSString *key in dict.allKeys) { ... }
I got the solution
NSDictionary *myDict = #{#"one":#"1",#"two":#"2"};
NSMutableArray *arrayObject = [[NSMutableArray alloc]init];
NSMutableArray *arrayKey = [[NSMutableArray alloc]init];
NSMutableArray *arrayObjectKey = [[NSMutableArray alloc]init];
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
for (NSString *stringValue in myDict.allValues)
{
[arrayObject addObject:stringValue];
}
for (NSString *stringKey in myDict.allKeys)
{
[arrayKey addObject:stringKey];
}
for(int i = 0;i<[arrayKey count];i++)
{
dict = [[NSMutableDictionary alloc]initWithObjectsAndKeys:[NSString stringWithFormat:#"%#",[arrayKey objectAtIndex:i]],#"key",nil];
[dict setObject:[NSString stringWithFormat:#"%#",[arrayObject objectAtIndex:i]] forKey:#"value"];
[arrayObjectKey addObject:dict];
}
NSLog(#"The arrayObjectKey is - %#",arrayObjectKey);
The Output is
The arrayObjectKey is -
(
{
key = one;
value = 1;
},
{
key = two;
value = 2;
}
)
Create the dictionary:
NSDictionary *myDict = [NSDictionary dictionaryWithObjectsAndKeys:#"1",#"One",#"2","Two",nil];
Get a value out using:(this example tmp will be 1)
NSString *tmp = [myDict objectForKey:#"One"];
Display the output in console:
NSLog(#"%#",tmp);
To display the whole NSDictionary
NSLog (#"contents of myDict: %#",myDict);
What you are doing is creating a dictionary with key-value pairs. I think what you want to do is have an array with dictionaries.
NSArray *myArray = #[#{#"one":#"1"}, #{#"two":#"2"}];
for (NSDictionary* tmp in myArray) {
NSLog(#"%#",tmp);
}
However I don't see a point in doing this. What you could do is:
NSDictionary *myDict = #{#"one":#"1",#"two":#"2"};
for (NSString* key in [myDict allKeys]) {
NSLog(#"%# = %#", key, myDict[key]);
}

Sort dictionary of dictionaries in Objective C

I have a dictionary of dictionaries (for countries) as below:
US = {
areaCode = 1;
code = US;
name = "United States";
};
UY = {
areaCode = 598;
code = UY;
name = Uruguay;
};
UZ = {
areaCode = 998;
code = UZ;
name = Uzbekistan;
};
How could I sort it with "name" key of inner dictionary ?
More Explanation and Edit:
I created this dictionary (key/value system) as below:
NSString *countriesPath = [bundle pathForResource:#"countries" ofType:#"csv"];
NSMutableDictionary *countries = [NSMutableDictionary dictionary];
fileContents = [NSString stringWithContentsOfFile:countriesPath usedEncoding:nil error:nil];
rows = [fileContents componentsSeparatedByString:#"\n"];
for (NSString *row in rows){
NSArray* columns = [row componentsSeparatedByString:#","];
NSDictionary *CountryRowData = #{
#"code": columns[0],
#"name": columns[1],
#"areaCode": columns[2]
};
countries[columns[0]]= CountryRowData;
}
_countries = countries;
You can't sort a dictionary—it's an unordered collection. You can sort an array of keys, though:
NSDictionary *countries;
NSArray *sortedKeys = [[countries allKeys] sortedArrayUsingComparator:^NSComparisonResult(NSString *key1, NSString *key2) {
return [countries[key1][#"name"] compare:countries[key2][#"name"]];
}];
// sortedKeys is now ( US, UY, UZ )

How to replace the value of the key in NSMutableDictionary based on the another key value pair

I have one NSArray with NSMutableDictionaries .Example testArray =[dict1,dict2,dict3,dict4].
Each dictionary in the array is something like
dict1= {
country = "INDIA";
flag = "A";
Currency = "Rupees";
rate = 10;
}
The all values are changeable. Sometimes
dict1 = {
country = "USA";
flag = "SA";
Currency = "Dollar";
rate = 50;
}
I need to update the value of the key rate of all dictionaries in the testArray if country = "INDIA" and flag = "A" and Currency = "Rupees" and Do not need to change the value of the rate key all other dictionaries in side the testArray.
Just try the below.
for(NSMutableDictionary *dic in array)
{
if([[dic valueForKey:#"country"] isEqualToString:#"INDIA"] &&
[[dic valueForKey:#"flag"] isEqualToString:#"A"] &&
[[dic valueForKey:#"Currency"] isEqualToString:#"Rupees"])
{
[dic setValue:#"100" forKey:#"rate"];
}
}
Here is a complete example what you need
NSDictionary *dict1 = #{
#"country" : #"INDIA",
#"flag" : #"A",
#"Currency" : #"Rupees",
#"rate" : #10
};
NSDictionary *dict2 = #{
#"country" : #"USA",
#"flag" : #"SA",
#"Currency" : #"Dollar",
#"rate" : #50
};
NSArray *testArray = #[dict1, dict2];
NSMutableArray *testMutableArray = [testArray mutableCopy];
for (int i = 0; i < testMutableArray.count; i++) {
NSDictionary *country = testMutableArray[i];
if ([country[#"country"] isEqualToString:#"INDIA"] &&
[country[#"flag"] isEqualToString:#"A"] &&
[country[#"Currency"] isEqualToString:#"Rupees"])
{
NSMutableDictionary *countryMutable = [country mutableCopy];
countryMutable[#"rate"] = #100;
testMutableArray[i] = [countryMutable copy];
}
}
testArray = [testMutableArray copy];
Use NSMutableArray instead of NSArray.
then,
NSDictionary *dict = [testArray objectAtIndex:0];
dict[#"rate"] = #"11";
[testArray replaceObjectAtIndex:0 withObject:dict];
Hope this will help you.

Using NSPredicate to filter an object and a key(that needs to be split)

I have the following dictionary set up(Object, Key)
0, "10;0.75,0.75"
1, "0;2.25,2.25"
3, "1;3.5,2.0"
4, "1;4.5,3.0"
5, "2;6.0,5,0"
What I want to filter will be based on the object AND the key. The object is a NSNumber. The key is a string but i really don't want the entire string. I want to split the string separated by the semicolon and take the first index of the split which would yield the strings 10,0,1,1 or 2 depending on which object I was looking for.
As a specific example:
Are there any keys that are equal to #"1" with an object that is greater than 3.
In this case i should expect back YES since object 4 has a key that is equal to #"1", after i do the split.
I guess I was looking for a clever way to define a NSPredicate to do the split on the key separated by the semicolon and then filter(compare, etc) based on that. Let me know if you have any questions or need additional info.
A very naive implementation that I could think of
- (BOOL)hasKey:(NSString *)key withValueGreaterThan:(id)object{
NSDictionary *dictionary = #{#"10;0.75,0.75": #0,
#"0;2.25,2.25" : #1,
#"1;3.5,2.0" : #3,
#"1;4.5,3.0" : #4,
#"2;6.0,5,0" : #5};
NSPredicate *keyPredicate = [NSPredicate predicateWithFormat:#"SELF BEGINSWITH %#",key];
NSArray *filteredKeys = [[dictionary allKeys]filteredArrayUsingPredicate:keyPredicate];
for (NSString *k in filteredKeys) {
NSNumber *value = dictionary[k];
if (value>object) {
return YES;
}
}
return NO;
}
Use
BOOL hasValue = [self hasKey:#"1;" withValueGreaterThan:#3];
Sample Code:
NSDictionary* dict = #{ #"10;0.75,0.75":#0,
#"0;2.25,2.25":#1,
#"1;3.5,2.0":#3,
#"1;4.5,3.0":#4,
#"2;6.0,5,0":#5};
__block NSString* foundKey = nil;
[dict enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSNumber* obj, BOOL *stop) {
//here goes condition
//get substr
NSArray* arr = [key componentsSeparatedByString:#";"];
int num = [[arr objectAtIndex:0]integerValue];
if ((num == 1)&&([obj integerValue]>3)) {
foundKey = key;
stop = YES;
}
}];
if (foundKey) {
NSLog(#"%#:%#",foundKey,[dict objectForKey:foundKey]);
}
Just use the following method:
-(BOOL)filterFromDictionary:(NSDictionary*)dict keyEqual:(NSString*)key greaterthanObj:(NSString*)obj
{
NSArray *allKeys = [dict allKeys];
for (NSString *eachkey in allKeys) {
NSString *trimmedKey = [self trimKeyuntill:#";" fromString:eachkey];
NSString *trimmedValue = [dict objectForKey:eachkey];
if ([trimmedKey isEqualToString:key] && [trimmedValue intValue] > [obj intValue]) {
return YES;
}
}
return NO;
}
call the above method with your dictionary like:
NSDictionary *dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"1",#"1",#"3",#"4",#"5", nil] forKeys:[NSArray arrayWithObjects:#"10;0.75,0.75",#"0;2.25,2.25",#"1;3.5,2.0",#"1;4.5,3.0",#"2;6.0,5,0", nil]];
[self filterFromDictionary:dict keyEqual:#"1" greaterthanObj:#"3"]
I assumed all your objects are nsstrings. otherwise change the intValue

Getting values from NSDictionary in foreach?

I have a view that has tableviewcells on it, loaded with different "key values" as the label. When I tap on one I open another view. However here, I pass the dictionary for just that key, for example I would pass this:
{
key = Budget;
value = {
"2012 Budget Report" = {
active = 0;
author = "xxxxx xxxxxx";
date = "October 27, 2012";
description = "Example";
dl = "53 downloads";
email = "xxx#xxxxx.com";
ext = DOCX;
fortest = "Tuesday, November 6";
id = 5;
subject = budget;
testdate = "Tuesday, November 6";
title = "Budget spreadSheet";
};
"2005 - 2008 Budget Report" = {
active = 0;
author = "xxxxxxx xxxxx";
date = "November 3, 2012";
description = "Example";
dl = "18 downloads";
email = "xxxxx#xxxxx.com";
ext = DOCX;
title = "Budget report";
};
};
}
How do I get each of these values? Thanks.
Please note: the titles in value array are subject to change... More could be added, one could be deleted, so I need a general solution.
Considering the dictionary you passed is saved in iDictionary.
NSDictionary *iDictionary // Input Dictionary;
NSDictionary *theValues = [NSDictionary dictionaryWithDictionary:[iDictionary valueForKey:#"value"]];
for (NSString *aKey in [theValues allKeys]) {
NSDictionary *aValue = [theValues valueForKey:aKey];
NSLog(#"Key : %#", aKey);
NSLog(#"Value : %#", aValue);
// Extract individual values
NSLog(#"Author : %#", [aValue objectForKey:#"author"]);
// If the titles are dynamic
for (NSString *aSubKey in [aValue allKeys]) {
NSString *aSubValue = [aValue objectForKey:aSubKey];
NSLog(#"SubKey : %#, SubValue = %#", aSubKey, aSubValue);
}
}
NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
NSArray *arrBudget= [jsonDictionary objectForKey:#"Budget"];
So here arrBudget will contain All the values And you can Pass the array to detail view.
Another approach if keys and objects are useful in the "foreach" logic :
NSDictionary *dict = #{
#"key1": #"value1",
#"key2": #"value2",
#"key3": #"value3",
};
[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSLog(#"Your key : %#", key);
NSLog(#"Your value : %#", [obj description]);
// do something...
}];

Resources