How to add NSDictionary of dictionaries to NSArray? - iphone

I have a dictionary of dictionaries. This is the structure of my main dictionary:
The content of dictionary(
{
mondaysSales= {
totalSale = "1234.99";
},
tusdaySales= {
totalSale = "1234.99";
},
wednesdaySale={
totalSale = "1234.99";
},
thursdaySale{
totalSale = "1234.99";
},
fridaySale{
totalSale = "1234.99";
}
)
but I want to add each day with the day key to a array. For example:
this would be one of the entries of the array:
fridaySale{
totalSale = "1234.99";
}
Any of you how can accomplish this?, I'll really appreciate your help.

You can loop through the dictionary and add it to the array. Note that dictionaries are not sorted and you probably won't end up with a correct order for your weekdays
NSMutableArray *array = [#[] mutableCopy]
for (NSString* key in dictionary) {
id value = [dictionary objectForKey:key];
[array addObject:value];
}

Why not create a new object type and add that to the array?
StorageObject.h:
#interface StorageObject:NSObject
#property (nonatomic, retain) NSString *day;
#property (nonatomic, retain) NSString *saleType;
#property (nonatomic, retain) NSNumber *saleValue;
#end
StorageObject.m:
#implementation StorageObject
#synthesize
day = _day,
saleType = _saleType,
saleValue = _saleValue;
- (void)dealloc
{
[_day release];
[_saleType release];
[_saleValue release];
[super dealloc];
}
#end
Now just loop through your NSDictionary using:
for(NSString *key in [dictionary1 allKeys])
{
NSDictionary *innerDictionary = [dictionary1 objectForKey:key];
}
For every dictionary returned in that loop, instantiate your custom storage object and add it to the array.

I figure out solution:
NSMutableDictionary *tempDict=[[NSMutableDictionary alloc]init];
[tempDict setObject:[mainDic objectForKey:key] forKey:key];
[myArray addObject:tempDict];

Assuming you have a dictionary of dictionaries:
You can do
NSMutableArray *list = [#[] mutableCopy];
for (NSString *key in [mainDictionary allKeys]) {
NSDictionary *dict = #{
key : [mainDictionary objectForKey:key],
};
[list addObject:dict];
}

There is an easy way to do this just don't create an NSDictionary and instead create an NSArray, by doing the following
NSArray *Array = #[#{#"friday sale, totalSale" : #"1234.99"}]
Or if you want to have specifics gotten from anything else in it.
NSInteger value = 1;
NSArray *Array = #[#{ #"Friday sale, totalSale" : [NSString stringWithFormat:#"%ld", (long)value]}];
Then you get this value from simply saying,
NSString *somestring = Array["Friday sale, totalSale"];

Related

How to swap `NSMutableDictionary` key and values in place?

I have a NSMutableDictionary and I want to swap values & keys. i.e, after swapping values becomes keys and its corresponding keys with become values All keys and values are unique. Looking for an in place solution because size is very big . Also, the keys and values are NSString objects
NSMutableDictionary *d = [NSMutableDictionary dictionaryWithDictionary:#{
#"key1" : #"value1",
#"key2" : #"value2"}];
for (NSString *key in [d allKeys]) {
d[d[key]] = key;
[d removeObjectForKey:key];
}
NSLog(#"%#", d); // => { value1 : key1,
// value2 : key2 }
Assumptions
unique values (as they will become keys)
values conform to NSCopying (same as above)
no value is equal to any key (otherwise colliding names will be lost in the process)
Here is another way to invert dictionary. The simplest for me.
NSArray *keys = dictionary.allKeys;
NSArray *values = [dictionary objectsForKeys:keys notFoundMarker:[NSNull null]];
[dictionary removeAllObjects]; // In case of huge data sets release the contents.
NSDictionary *invertedDictionary = [NSDictionary dictionaryWithObjects:keys forKeys:values];
[dictionary setDictionary:invertedDictionary]; // In case you want to use the original dictionary.
EDIT: I had written a few lines of codes to get the OP started into the task of creating his own algorithm. The answer was not well received so I have crafted a full implementation of an algorithm that does what he asks, and goes one step further.
Advantages:
Makes no assumptions regarding the contents of the dictionary, for example, the values need not conform to the 'NSCopying' protocol
Transverses the whole hierarchy of a collection, swapping all the keys
It's fast since it uses recursion and fast enumeration
Does not alter the contents of the original dictionary, it creates a brand new one
Code has been implemented through categories to both collections:
#interface NSDictionary (Swapping)
- (NSDictionary *)dictionaryBySwappingKeyWithValue;
#end
#interface NSDictionary (Swapping)
- (NSDictionary *)dictionaryBySwappingKeyWithValue
{
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithCapacity:self.count];
[self enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
id newKey = nil;
if ([value isKindOfClass:[NSDictionary class]]) {
newKey = [value dictionaryBySwappingKeyWithValue];
} else if ([value isKindOfClass:[NSArray class]]) {
newKey = [value arrayBySwappingKeyWithValue];
} else {
newKey = value;
}
if (![newKey conformsToProtocol:#protocol(NSCopying)]) {
newKey = [NSValue valueWithNonretainedObject:newKey];
}
mutableDictionary[newKey] = key;
}];
return [NSDictionary dictionaryWithDictionary:mutableDictionary];
}
#end
and...
#interface NSArray (Swapping)
- (NSArray *)arrayBySwappingKeyWithValue;
#end
#implementation NSArray (Swapping)
- (NSArray *)arrayBySwappingKeyWithValue
{
NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:self.count];
[self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[NSDictionary class]]) {
NSDictionary *newDict = [obj dictionaryBySwappingKeyWithValue];
mutableArray[idx] = newDict;
} else if ([obj isKindOfClass:[NSArray class]]) {
NSArray *newArray = [obj arrayBySwappingKeyWithValue];
mutableArray[idx] = newArray;
} else {
mutableArray[idx] = obj;
}
}];
return [NSArray arrayWithArray:mutableArray];
}
#end
As an example, assume you have a dictionary with the following structure:
UIView *view = [[UIView alloc] init];
NSDictionary *dict = #{#"1" : #"a",
#"2" : #[ #{ #"5" : #"b" } ],
#"3" : #{#"6" : #"c"},
#"7" : view};
NSDictionary *newDict = [dict dictionaryBySwappingKeyWithValue];
Printing the newDict object in the console will give you this output:
(lldb) po mutableDictionary
{
a = 1;
({b = 5;}) = 2;
{c = 6;} = 3;
"<30b50617>" = 7;
}
As you can see, not only have the keys and values been swapped at the first level of the hierarchy, but deep inside each collection.
"<30b50617>" represents the UIView object wrapped inside a NSValue. Since UIView does not comply to the NSCopying protocol, it needs to be handled this way if you want it to be a key in your collection.
Note: Code was done in a couple of minutes. Let me know if I missed something.
for (NSString *key in [myDictionary allKeys]) {
NSString *value = [responseDataDic objectForKey:key];
[myDictionary removeObjectForKey:key];
[myDictionary addObject:key forKey:value];
}
Assumption:
No key = value;
Complexity:
No extra space required. Will loop through once and replace all key value pairs.
NSArray* allKeys = [theDict allKeys];
NSArray* allValues = [theDict allValues];
NSMutableDictionary* newDict = [NSMutableDictionary dictionaryWithObjects:allKeys forKeys:allValues];

Sort array with a count value

I have an array which contains some strings. For each character of a string an integer value is assigned. For example a=2,b=5,c=6 ,o=1,k=3 etc
The final value in the a string is the sum of the character's value. So that for an example string "BOOK" the string will be stored as "BOOK (7)". Similarly every string will have a final integer value. I would like to sort these array with these final integer values stored in the string which is present in each array index. The array contains more than 200,000 words. So the sorting process should be pretty fast. Is there any method for it?
A brutal quick example could be, if your strings structure is always the same, like "Book (7)" you can operate on the string by finding the number between the "()" and then you can use a dictionary to store temporally the objects:
NSMutableArray *arr=[NSMutableArray arrayWithObjects:#"Book (99)",#"Pencil (66)",#"Trash (04)", nil];
NSLog(#"%#",arr);
NSMutableDictionary *dict=[NSMutableDictionary dictionary];
//Find the numbers and store each element in the dictionary
for (int i =0;i<arr.count;i++) {
NSString *s=[arr objectAtIndex:i];
int start=[s rangeOfString:#"("].location;
NSString *sub1=[s substringFromIndex:start];
NSString *temp1=[sub1 stringByReplacingOccurrencesOfString:#"(" withString:#""];
NSString *newIndex=[temp1 stringByReplacingOccurrencesOfString:#")" withString:#""];
//NSLog(#"%d",[newIndex intValue]);
[dict setValue:s forKey:newIndex];
}
//Sorting the keys and create the new array
NSArray *sortedValues = [[dict allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSMutableArray *newArray=[[NSMutableArray alloc]init];
for(NSString *valor in sortedValues){
[newArray addObject:[dict valueForKey:valor]];
}
NSLog(#"%#",newArray);
This prints:
(
"Book (99)",
"Pencil (66)",
"Trash (04)"
)
(
"Trash (04)",
"Pencil (66)",
"Book (99)"
)
as i understand, you want to sort an array which contains string formated in the following
a=3
and you want to sort according to the number while ignoring the character.
in this case the following code will work with you
-(NSArray *)Sort:(NSArray*)myArray
{
return [myArray sortedArrayUsingComparator:(NSComparator)^(id obj1, id obj2)
{
NSString *first = [[obj1 componentsSeparatedByString:#"="] objectAtIndex:1];
NSString *second = [[obj2 componentsSeparatedByString:#"="] objectAtIndex:1];
return [first caseInsensitiveCompare:second];
}];
}
How to use it:
NSArray *arr= [[NSArray alloc] initWithObjects:#"a=3",#"b=1",#"c=4",#"f=2", nil];
NSArray *sorted = [self Sort:arr];
for (NSString* str in sorted)
{
NSLog(#"%#",str);
}
Output
b=1
f=2
a=3
c=4
Try this methods
+(NSString*)strTotalCount:(NSString*)str
{
NSInteger totalCount = 0;
// initial your character-count directory
NSDictionary* characterDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:2], [NSString stringWithUTF8String:"a"],
[NSNumber numberWithInt:5], [NSString stringWithUTF8String:"b"],
[NSNumber numberWithInt:6], [NSString stringWithUTF8String:"c"],
[NSNumber numberWithInt:1], [NSString stringWithUTF8String:"o"],
[NSNumber numberWithInt:3], [NSString stringWithUTF8String:"k"],
nil];
NSString* tempString = str;
for (NSInteger i =0; i<tempString.length; i++) {
NSString* character = [tempString substringWithRange:NSMakeRange(i, 1)];
character = [character lowercaseString];
NSNumber* count = [characterDictionary objectForKey:character];
totalCount += [count integerValue];
};
return [NSString stringWithFormat:#"%#(%d)",str,totalCount];
}
The test sentence:
NSLog(#"%#", [ViewController strTotalCount:#"BOOK"]);
will output " BOOK(10) "
You may change the ViewController to you own class name;
First - create a custom object to save your values. Don't put the value inside the string.
Sorting is not your base problem. The problem is that you are saving values into a string from where they are difficult to extract.
#interface StringWithValue
#property (nonatomic, copy, readwrite) NSString* text;
#property (nonatomic, assign, readwrite) NSUInteger value;
- (id)initWithText:(NSString*)text;
- (NSComparisonResult)compare:(StringWithValue*)anotherString;
#end
#implementation StringWithValue
#synthesize text = _text;
#synthesize value = _value;
- (id)initWithText:(NSString*)text {
self = [super init];
if (!self) {
return nil;
}
self.text = text;
self.value = [self calculateValueForText:text];
return self;
}
- (NSComparisonResult)compare:(StringWithValue*)anotherString {
if (self.value anotherString.value) {
return NSOrderedDescending;
}
else {
return NSOrderedSame;
}
}
- (NSString*)description {
return [NSString stringWithFormat:#"%# (%u)", self.text, self.value];
}
#end
Sorting the array then would be a simple use of sortUsingSelector:.
Note this will beat all other answers in performance as there is no need to parse the value with every comparison.

Convert an object into Json using SBJson or other JSON library

I need a easy to use library whit examples for converting NSObjects to JSON and back again, I found a ton of parseing examples on the net for parsing JSon but not too much on converting NSObject to JSON using SBJSON, Anybody body have a good tutorial or a sample code to convert NSObject to JSON ?
With SBJSON, it's really simple.
NSString *myDictInJSON = [myDict JSONRepresentation];
NSString *myArrayInJSON = [myArray JSONRepresentation];
Of course, to go the other way array, do:
NSDictionary *myDict = [myDictInJSON JSONValue];
NSArray *myArray = [myArrayInJSON JSONValue];
Using SBJson, to convert a object to JSON string, you have to override the proxyForJson method. Like the following,
The .h file,
#interface MyCustomObject : NSObject {
NSString *receiverFirstName;
NSString *receiverMiddleInitial;
NSString *receiverLastName;
NSString *receiverLastName2;
}
#property (nonatomic, retain) NSString *receiverFirstName;
#property (nonatomic, retain) NSString *receiverMiddleInitial;
#property (nonatomic, retain) NSString *receiverLastName;
#property (nonatomic, retain) NSString *receiverLastName2;
- (id) proxyForJson;
- (int) parseResponse :(NSDictionary *) receivedObjects;
}
In the implementation file,
- (id) proxyForJson {
return [NSDictionary dictionaryWithObjectsAndKeys:
receiverFirstName, #"ReceiverFirstName",
receiverMiddleInitial, #"ReceiverMiddleInitial",
receiverLastName, #"ReceiverLastName",
receiverLastName2, #"ReceiverLastName2",
nil ];
}
And to get the object from the JSON string you have to write a parseResponse method like this,
- (int) parseResponse :(NSDictionary *) receivedObjects {
self.receiverFirstName = (NSString *) [receivedObjects objectForKey:#"ReceiverFirstName"];
self.receiverLastName = (NSString *) [receivedObjects objectForKey:#"ReceiverLastName"];
/* middleInitial and lastname2 are not required field. So server may return null value which
eventually JSON parser return NSNull. Which is unrecognizable by most of the UI and functions.
So, convert it to empty string. */
NSString *middleName = (NSString *) [receivedObjects objectForKey:#"ReceiverMiddleInitial"];
if ((NSNull *) middleName == [NSNull null]) {
self.receiverMiddleInitial = #"";
} else {
self.receiverMiddleInitial = middleName;
}
NSString *lastName2 = (NSString *) [receivedObjects objectForKey:#"ReceiverLastName2"];
if ((NSNull *) lastName2 == [NSNull null]) {
self.receiverLastName2 = #"";
} else {
self.receiverLastName2 = lastName2;
}
return 0;
}
From JSON String to Objects:
SBJsonParser *parser = [[SBJsonParser alloc] init];
// gives array as output
id objectArray = [parser objectWithString:#"[1,2,3]"];
// gives dictionary as output
id objectDictionary = [parser objectWithString:#"{\"name\":\"xyz\",\"email\":\"xyz#email.com\"}"];
From Objects to JSON String:
SBJsonWriter *writer = [[SBJsonWriter alloc] init];
id *objectArray = [NSArray arrayWithObjects:#"Hello",#"World", nil];
// Pass an Array or Dictionary object.
id *jsonString = [writer stringWithObject:objectArray];

iphone listview with several cells

I have been able to make the listview show a single field of data using parts of the code like below.
NSMutableArray *array;
..
..
array = [[NSMutableArray alloc] init];
[array addObject:#"John Doe"];
However I want to keep several fields, like:
Name
ID
Date of Birth
I assume the NSMutableArrary is a NSString but I need something like a struct in C that holds the fields I need.
The ID would be "Hidden" but I need to access it when the user clicks on the line. How I access the ID and the other fields? How do I set this up so the list has the information?
Does anyone have any example code that might explain how to do this?
EDIT #1: Thanks for the comments, but I am too new to iPhone and really need to find example code on how to do this. While the comments make it sound like can do this, I dont know where to start. Can someone post example code for the idea of 3 fields?
EDIT #2: I have tried everything so far, is the the correct way to do this or should I use the ideas below?
Userrec.m
#import "UserRec.h"
#implementation Userrec
#synthesize Name, ID;
-(id)initWithName:(NSString *)n ID:(NSString *)d {
self.Name = n;
self.ID = d;
return self;
}
#end
UserRec.h
#import <UIKit/UIKit.h>
#interface Userrec : NSObject {
NSString *Name;
NSString *ID;
}
#property (nonatomic, retain) NSString *Name;
#property (nonatomic, retain) NSString *ID;
-(id)initWithName:(NSString *)n ID:(NSString *)d;
#end
UserList.m
#synthesize userrecs;
…
- (void)viewDidLoad {
[super viewDidLoad];
NSString *Name = #"Name";
NSString *ID = #"IID";
Userrec *userrec = [[Userrec alloc] initWithName:Name ID:ID ];
[userrecs addObject:userrec];
NSLog(#"Count %d",[userrecs count]);
[userrec release];
NSLog(#"Count %d",[userrecs count]);
}
After I addobject and check the count its = 0. So I assume something is wrong?
NSMutableDictionary is the best way to go. You can do something as follows:
NSMutableDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:#"John Doe", #"Name", [NSNumber numberWithInt:5], #"ID", nil];
You can keep adding as many fields as you like with that same template, even NSArray objects. I'd look up the documentation if you have any more trouble. Remember, you can only store pointers to objects in an NSDictionary. Things like
NSMutableDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:#"John Doe", #"Name", 5, #"ID", nil];
won't work. Good Luck!
Take a look at an NSMutableDictionary it seems like the exact thing you would want to use
Edit:
Here's some sample code
NSMutableArray *myData = [[NSMutableArray alloc] init];
NSMutableDictionary *myRow = [[NSMutableDictionary alloc] init];
[myRow setObject:#"John Doe" forKey:#"Name"];
[myRow setObject:#"4738" forKey:#"ID"];
[myRow setObject:#"1/23/45" forKey:#"DOB"];
[myData addObject:myRow];
[myRow release];
//Repeat from dictioanry alloc through release for each row you need to add
To display this in a UITableView, you need to have a UITableViewController class. In there override the cellForRowAtIndexPath: function. here is a simple implementation of that function
-(UITableViewCell*) tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger row = [indexPath row];
static NSString *kCellID = #"cellID";
UITableViewCell *cell = nil;
cell = [tableView dequeueReuseableCellWithIdentifier:kCellID];
if ( cell == nil )
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellID] autorelease];
}
NSMutableDictionary curRow = [myData objectAtIndex:row];
cell.textLabel.text = [curRow objectForKey:#"Name"];
return cell;
}

How to create Array of Array in iPhone?

I want to create a nested array or multidimensional array.
In my data is,
FirstName class year dept lastName
Bob MBA 2000 Comp Smith
Jack MS 2001 Comp McDonald
NSMutableArray *section = [[NSMutableArray alloc] init];
I want to put my data into the section Array.
Eg:
section[0] = [FirstName,LastName];
section[1] = [class, year, dept];
So how can i put the values into array like that.
Please help me out.
Thanks
I would recommend creating a custom data storage class. You could call it PDPerson.h You'll also need the .m file. For each property, do something like this:
In the .h: Declare each of your properties like so:
#interface PDPerson : NSObject{
}
#property(nonatomic, retain) NSString *firstName;
#property(nonatomic, retain) NSString *lastName;
#property(nonatomic, retain) NSString *class;//May want to consider renaming
#property(nonatomic, retain) NSString *year;
#property(nonatomic, retain) NSString *dept;
#end
Then in the .m:
#implementation
#synthesize firstName, lastName;
#synthesize class, year dept;
-(void)dealloc{
[firstName release];
[lastName release];
[class release];
[year release];
[dept release];
}
Each time you want to create a new "Person" in your array, do this:
PDPerson *person = [[PDPerson alloc]init];
You can then easily set the properties of the object like so:
person.firstName = #"John";
person.lastName = #"Smith";
person.class = #"Math";
person.year = #"1995";
person.dept = #"Sciences";
And retrieve them:
firstNameLabel.text = person.firstName;
The nice thing about these objects is that all you have to do now is add the person object to your array:
NSMutableArray *personArray = [[NSMutableArray alloc] init];
[personArray addObject:person];
NSArray *section1 = [NSArray arrayWithObjects: #"1,1", #"1,2", #"1,3", nil];
NSArray *section2 = [NSArray arrayWithObjects: #"2,1", #"2,2", #"2,3", nil];
NSArray *section3 = [NSArray arrayWithObjects: #"3,1", #"3,2", #"3,3", nil];
NSArray *sections = [NSArray arrayWithObjects: section1, section2, section3, nil];
int sectionIndex = 1;
int columnIndex = 0;
id value = [[sections objectAtIndex:sectionIndex] objectAtIndex:columnIndex];
NSLog(#"%#", value); //prints "2,1"
Be warned, this isn't a flexible way of storing data. Consider using CoreData or creating your own classes to represent the data.
You can just nest multiple NSArray instances within an NSArray.
For example:
NSMutableArray* sections = [[NSMutableArray alloc] init];
for (int i = 0; i < numberOfSections; i++)
{
NSMutableArray* personsInSection = [[NSMutableArray alloc] init];
[sections insertObject:personsInSection atIndex:i];
for (int x = 0; x < numberOfPersons; x++)
{
Person* person = [[Person alloc] init];
[personsInSection insertObject:person atIndex:x];
}
}
This may seem like overkill when coming from languages such as C++ or Java, where multidimensional arrays can be created simply by using multiple sequare brackets. But this is way things are done with Objective-C and Cocoa.