Sort dictionary of dictionaries in Objective C - ios

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 )

Related

Iterate through two layers of NSDictionary

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"];

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]);
}

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 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.

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