Copying a dictionary with multiple sub dictionaries and only returning certain keys from the sub dictionaries - iphone

In my current iPhone project, I have a created a dictionary that groups the sub dictionaries by the first letter of the "Name" key. NSLog returns the following. I would like to create an identical dictionary that only shows the "Name" key under each initial letter key. What is the best way for making a copy of some of the items in the sub dictionaries? The ObjectForKey methods will select only the items for the initial letter (ex: "B" or "C"). Please let me know if I didn't explain this clearly enough.
Thanks!
sectionedDictionaryByFirstLetter:{
B = (
{
Name = "B...A Name Starting with B";
Image = "ImageName1.png";
Text = "Some Text";
}
);
C = (
{
Name = "C...A Name Starting with C";
Image = "ImageName2.png";
Text = "Some Text";
}
);
N = (
{
Name = "N...A Name Starting with N";
Image = "ImageName3.png";
Text = "Some Text";
},
{
Name = "N...A Name Starting with N";
Image = "ImageName4.png";
Text = "Some Text";
},
{
Name = "N...A Name Starting with N";
Image = "ImageName5.png";
Text = "Some Text";
}
);
}
The final result I'm looking for is:
sectionedDictionaryByFirstLetter:{
B = (
{
Name = "B...A Name Starting with B";
}
);
C = (
{
Name = "C...A Name Starting with C";
}
);
N = (
{
Name = "N...A Name Starting with N";
},
{
Name = "N...A Name Starting with N";
},
{
Name = "N...A Name Starting with N";
}
);
}

Core Foundation has a great function, CFDictionaryApplyFunction (I wish they ported its functionality to NSDictionary too). However, NSDictionary and CFDictionary are "toll-free bridges", meaning that you can cast between them at no cost.
So, the solution would be to create an applier function, SaveName, which would be used in the CFDictionaryApplyFunction above. Example:
void SaveName(const void* key, const void* value, void* context) {
NSMutableDictionary* result = (NSMutableDictionary*) context;
NSDictionary* dataDict = (NSDictionary*) value;
NSString* letterKey = (NSString*) key;
[result setObject:[dataDict valueForKey:#"Name"] forKey:#letterKey];
}
void main() {
NSDictionary* exampleDict = .. ;
NSMutableDictionary* resultDict = [NSMutableDictionary dictionary];
CFDictionaryApplyFunction((CFDictionaryRef)exampleDict, SaveName, (void*)resultDict);
// now, the resultDict contains key-value pairs of letter-name!
}
My code assumes that there is only one object in the "value" dictionary. You can change SaveName to take into consideration your own data structure, but that's basically the way to do it.

NSMutableDictionary* newDict = [NSMutableDictionary dictionary];
for (NSString* key in sectionedDictionaryByFirstLetter) {
NSMutableArray* newList = [NSMutableArray array];
[newDict setObject:newList forKey:key];
for (NSDictionary* entry in [sectionedDictionaryByFirstLetter objectForKey:key]) {
NSString* name = [entry objectForKey:#"Name"];
[newList addObject:[NSDictionray dictionaryWithObject:name forKey:#"Name"]];
}
}

Related

SBJson parse attempt -- objective C

I'm trying to parse the following JSon (which was validated I think last time I checked):
{
"top_level" = (
{
"download" = "http:/target.com/some.zip";
"other_information" = "other info";
"notes" = (
{
obj1 = "some text";
obj2 = "more notes";
obj3 = "some more text still";
}
);
title = "name_of_object1";
},
{
"download" = "http:/target.com/some.zip";
"other_information" = "other info";
"notes" = (
{
obj1 = "some text";
obj2 = "more notes";
obj3 = "some more text still";
}
);
title = "name_of_object2";
},
{
"download" = "http:/target.com/some.zip";
"other_information" = "other info";
"notes" = (
{
obj1 = "some text";
obj2 = "more notes";
obj3 = "some more text still";
}
);
title = "name_of_object3";
}
);
}
My attempt is using the following:
NSDictionary *myParsedJson = [myRawJson JSONValue];
for(id key in myParsedJson) {
NSString *value = [myParsedJson objectForKey:key];
NSLog(value);
}
Error:
-[__NSArrayM length]: unrecognized selector sent to instance 0x6bb7b40
Question:
It seems to me that JSon value makes myParsedJson object an NSArray instead of a NSDictionary.
How would I iterate through the objects called name_of_object and access each of the nested dictionaries? Am I going about it the right way?
The first argument of NSLog must be a string. Try this:
NSLog(#"%#", value);
Your value is not a string, just because you've typed it so.
Based on the structure you posted you will have an array as your
top-level object.
NSDictionary *myParsedJson = [myRawJson JSONValue];
for(id key in myParsedJson) {
id value = [myParsedJson objectForKey:key];
NSLog(#"%#", value);
}
The %# syntax in NSLog causes the -description method to be
called on value; this method returns an NSString. That means
that you could do NSLog([value description]); but this is
generally not a good idea. (Someone could craft malicious input that could crash your app.)

Objective-C for in loop nested NSDictionaries

I've got this data I get from an XML feed and parse as NSDictionaries. The data structure is like this:
item = {
address = {
text = "1 Union Street";
};
data = {
text = "Hello.";
};
event_date = {
text = "2012-02-27";
};
event_type = {
text = pubQuiz;
};
latitude = {
text = "57.144994";
};
longitude = {
text = "-2.10143170000003";
};
name = {
text = "Mobile Tester";
};
picture = {
text = "public://pictures/event_default.png";
};
time = {
text = "23.00";
};
vname = {
text = Test;
};
}
//More items
Each sub-section, ie, address, data, event_date etc are all NSDictonaries.
I would like to iterate through the whole collection and grab the "text" inside each of the sections to create an array of "items" with these properties. I've tried using the for..in loop structure in Objective-C but haven't had any success so far. Has anyone got a few pointers? I'm happy to read through any good tutorials or examples on how to traverse nested NSDictionaries.
EDIT:
Alright so, after parsing the XML I get that structure up there. What I would like to do is traverse the "item" structure to extract the "text" fields of all the inner dictionaries - something like this:
foreach(item in array of dictionaries) {
myItem.address = item.address.text;
myItem.data = item.data.text;
...
}
And so on. I hope this makes it a little clearer.
So, the part where I'm stuck is where I want to set the properties of the item while traversing the NSDictionaries. This is what I have so far:
for(NSDictionary *item in self.eventsArray) {
for (NSDictionary *key in [item allKeys]) {
NSLog(#"%#", key);
id value = [item objectForKey:key];
if ([value isKindOfClass:[NSDictionary class]]) {
NSDictionary* newDict = (NSDictionary*)value;
for (NSString *subKey in [newDict allKeys]) {
NSLog(#"%#", [newDict objectForKey:subKey]);
}
}
}
}
Which outputs:
address
1 Union Street
data
Hello.
...
I'm just not sure how to select the proper attribute in the object I'm creating to set the required property, if that makes any sense?
You can create a new dictionary called items from the original one (called here dictionaries) :
NSMutableDictionary *items = [[NSMutableDictionary alloc] init];
for (NSDictionary *dict in dictionaries)
{
[items setValue:[dict objectForKey:#"text"] forKey:[dict description]];
}
It will create the following dictionary:
item = {
address = "1 Union Street",
data = "Hello.",
....
}
To get the items I did the following:
id eventsArray = [[[[XMLReader dictionaryForXMLData:responseData error:&parseError] objectForKey:#"root"] objectForKey:#"events"] objectForKey:#"event"];
if([eventsArray isKindOfClass:[NSDictionary class]])
{
//there's only one item in the XML, so there's only an NSDictionary created.
for(NSString *item in (NSDictionary*)eventsArray)
{
//check what each item is and deal with it accordingly
}
}
else
{
//There's more than one item in the XML, an array is created
for(NSDictionary *item in (NSArray*)eventsArray)
{
for (NSString *key in [item allKeys])
{
//check what value key is and deal with it accordingly
}
}
}
And that allows me to access all elements.

How do I properly populate the UITableView NSArray from a NSDictionary created using JSONKit?

Sorry for the long question but that best summarizes what I am trying to do:
My JSON Looks like:
{
4e8cf1d6c7e24c063e000000 = {
"_id" = {
"$id" = 4e8cf1d6c7e24c063e000000;
};
author = faisal;
comments = (
{
author = adias;
comment = amazing;
},
{
author = nike;
comment = "I concur";
}
);
created = {
sec = 1317772800;
usec = 0;
};
text = "This is a random post";
title = "post # 1";
type = (
punjabi
);
};
4e91fd49c7e24cda74000000 = {
"_id" = {
"$id" = 4e91fd49c7e24cda74000000;
};
author = draper;
comments = (
{
author = adias;
comment = "amazing again";
}
);
created = {
sec = 1318118400;
usec = 0;
};
text = "This is a random post again";
title = "post # 2";
type = (
punjabi
);
};
}
What I would like to do is to ultimately have a UTTableview with each row having a title (text from above JSON):
This is the code I have so far:
NSString *responseString = [request responseString];
NSDictionary *resultsDictionary = [responseString objectFromJSONString];
How do I put everything in an array for the UITableView? Again I am just a little rusty as I can swear I have done that before.
If you don't need the keys then you can convert it to an array by using allValues, e.g.:
NSArray *values = [resultsDictionary allValues];
Does your JSON really parse to an NSDictionary, or is this an NSArray containing NSDictionary instances? If the latter, then isn't it just something like:
NSString *textForCell = [[resultsArray objectAtIndex:row] valueForKey:#"title"];

Trouble reading JSON object using Obj-C

I am trying to read the following json object using the json-framework and obj-C
{
Sections = {
Now = "Wednesday 9 February 2011 02:40";
Section = (
{
Article = (
{
Exceprt = "text here";
ID = 49011;
Title = "text here";
Type = Politics;
audioCounter = 0;
commentsCounter = 0;
hasMore = false;
important = False;
likesCounter = 0;
photoCounter = 0;
time = "21:12";
timeStamp = "2/8/2011 9:14:16 PM";
timeStatus = True;
videoCounter = 0;
viewsCounter = 0;
},
{
Exceprt = "text here";
ID = 49010;
Title = "text here";
Type = Politics;
audioCounter = 0;
commentsCounter = 0;
hasMore = false;
important = True;
likesCounter = 0;
photoCounter = 0;
time = "20:45";
timeStamp = "2/8/2011 9:10:59 PM";
timeStatus = True;
videoCounter = 0;
viewsCounter = 0;
},
{
Exceprt = "text here";
ID = 49008;
Title = "text here";
Type = Politics;
audioCounter = 0;
commentsCounter = 0;
hasMore = false;
important = False;
likesCounter = 0;
photoCounter = 0;
time = "20:28";
timeStamp = "2/8/2011 9:09:44 PM";
timeStatus = True;
videoCounter = 0;
viewsCounter = 0;
}
);
ID = 22;
Name = "EN Live";
totalNews = 3416;
}
);
};
}
My intent is to have a list of the articles (list of dictionaries) so that I can later access them easily. I have been stuck a while on this and my code is giving me an error about calling a non existent method for NSArray which has led me to suspect that I am misunderstanding the json object. I am totally new to this and any help is greatly appreciated.
Here's my code:
NSDictionary *results = [jsonString JSONValue];
NSDictionary *Articles = [[results objectForKey:#"Sections"] objectForKey:#"Section"];
NSArray *ListOfArticles = [Articles objectForKey:#"Article"];
for (NSDictionary *article in ListOfArticles)
{
NSString *title = [article objectForKey:#"Title"];
NSLog(title);
}
Thanks !
First of all, those aren’t valid JSON data. Names (in name/value pairs) are strings and must be quoted. String values must always be quoted. Boolean values must be either true or false (lowercase). Check http://json.org/ and http://www.ietf.org/rfc/rfc4627.txt?number=4627 and http://jsonlint.com
Here’s the structure of your data:
The top level value is an object (dictionary)
This object has a name (key) called Sections whose value is itself another object (dictionary)
Sections has a name (key) called Section whose value is an array
Each element in the Section array is an object (dictionary)
Each element in the Section array has a name (key) called Article whose value is an array, as well as other names (keys): ID, title, totalNews
Each element in the Article array is an object
If your JSON data were valid, you could parse them as follows:
// 1.
NSDictionary *results = [jsonString JSONValue];
// 2.
NSDictionary *sections = [results objectForKey:#"Sections"];
// 3.
NSArray *sectionsArray = [sections objectForKey:#"Section"];
// 4.
for (NSDictionary *section in sectionsArray) {
// 5.
NSLog(#"Section ID = %#", [section objectForKey:#"ID"];
NSLog(#"Section Title = %#", [section objectForKey:#"Title"];
NSArray *articles = [section objectForKey:#"Article"];
// 6.
for (NSDictionary *article in articles) {
NSLog(#"Article ID = %#", [article objectForKey:#"ID"];
NSLog(#"Article Title = %#", [article objectForKey:#"Title"];
// …
}
}
Your JSON framework is probably parsing out an NSDictionary where you're expecting an NSArray. It'll let you assign an NSDictionary to an NSArray, but then you'll get a runtime exception when you attempt to call a method on your "array". Judging by the JSON you posted (which isn't correct JSON), this is what I would have my parsing code look like. The names of the NSDictionaries and NSArrays are simply named after the JSON attributes they represent.
NSDictionary* results = [jsonString JSONValue];
NSDictionary* sections = [results valueForKey:#"Sections"];
NSArray* section = [sections valueForKey:#"Section"];
NSArray article = [[section objectAtIndex:0] valueForKey:#"Article"];
for (NSDictionary* anArticle in article) {
NSLog(#"%#", [anArticle valueForKey:#"Title"]);
}

Loop through NSDictionary to create separate NSArrays

I have a large NSDictionary that I need to loop through and create separate NSArrays. Here are the contents:
(
{
id = {
text = "";
};
sub = {
text = " , ";
};
text = "";
"thumb_url" = {
text = "";
};
title = {
text = "2010-2011";
};
type = {
text = "title";
};
},
{
id = {
text = "76773";
};
sub = {
text = "December 13, 2010";
};
text = "";
"thumb_url" = {
text = "http://www.puc.edu/__data/assets/image/0004/76774/varieties/thumb.jpg";
};
title = {
text = "College Days - Fall 2010";
};
type = {
text = "gallery";
};
},
{
id = {
text = "";
};
sub = {
text = "";
};
text = "";
"thumb_url" = {
text = "";
};
title = {
text = "2009-2010";
};
type = {
text = "title";
};
},
{
id = {
text = "76302";
};
sub = {
text = "December 3, 2010";
};
text = "";
"thumb_url" = {
text = "http://www.puc.edu/__data/assets/image/0019/76303/varieties/thumb.jpg";
};
title = {
text = "Christmas Colloquy";
};
type = {
text = "gallery";
};
}
)
Each section has a type key, which I need to check. When it finds the title key, I need to add those to an array. Then the next sections that would use the gallery key needs to be in its own array until it finds another title key. Then the gallery keys after that into their own array.
I am using a UITableView section titles and content. So, the NSDictionary above should have one NSArray *titles; array, and two other arrays each containing the galleries that came after the title.
I have tried using a for loop but I just can't seem to get it right. Any ideas would be appreciated.
It's somewhat unclear by your log, but I'm guessing your NSDictionary has values of NSDictionary? If so:
NSMutableArray *titles = [NSMutableArray array];
// etc.
for (id key in sourceDictionary) {
NSDictionary *subDictionary = [sourceDictionary objectForKey:key];
if ([subDictionary objectForKey:#"type"] == #"title")
[titles addObject:[subDictionary objectForKey:#"title"]];
// etc.
}
Your question is a bit unclear... but this is how you would properly loop through an NSDictionary.
EDIT:
NSMutableDictionary *galleries = [NSMutableDictionary dictionary];
NSString *currentTitle;
for (id key in sourceDictionary) {
NSDictionary *subDictionary = [sourceDictionary objectForKey:key];
NSString *type = [subDictionary objectForKey:#"type"];
if (type == #"title") {
currentTitle = [subDictionary objectForKey:#"title"];
if ([galleries objectForKey:currentTitle] == nil)
[galleries setObject:[NSMutableArray array] forKey:currentTitle];
} else if (type == #"gallery" && currentTitle != nil)
[[galleries objectForKey:currentTitle] addObject:subDictionary];
}
After this loop, galleries will contain keys of type NSString (with values of the titles), and corresponding objects of type NSArray (with values of the gallery NSDictionarys). Hopefully this is what you were going for.
NSString *key;
for(key in someDictionary){
NSLog(#"Key: %#, Value %#", key, [someDictionary objectForKey: key]);
}
Modern Objective-C syntax:
NSMutableArray *things = [NSMutableArray array];
NSMutableArray *stuff = [NSMutableArray array];
NSMutableArray *bits = [NSMutableArray array];
[dictionaries enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
[things addObject:[obj valueForKeyPath:#"thing"]];
[stuff addObject:[obj valueForKeyPath:#"enclosing_object.stuff"]];
[bits addObject:[obj valueForKeyPath:#"bits"]];
}];