I have the following result of NSDictionary of Array
Bath = {
Keynsham = (
"nsham companies"
);
};
Bath = {
"Midsomer Norton" = (
"Keynsham companies"
);
};
Bath = {
"Norton Radstock" = (
"Keynsham taxi companies"
);
};
Birmingham = {
"Acock's Green" = (
"Acock's Green taxi companies"
);
};
Birmingham = {
"Alcester Lane's End" = (
"Alcester Lane's End taxi companies"
);
};
How can i combine the values and keys so that I end up with only one category as shown below;
Bath = {
"Norton Radstock" = (
"Keynsham taxi companies"
);
"Midsomer Norton" = (
"Keynsham companies"
);
Keynsham = (
"nsham companies"
);
};
I am not sure if this is the best way to explain it
the code is as follows
//all Nssarrays allocated/ initialised
NSURL *url=[NSURL URLWithString:#"http://y.php"];
NSData *data= [NSData dataWithContentsOfURL:url];
NSMutableArray *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:Nil];
//instantiate arrays to hold data
NSMutableDictionary *dictArray=[[NSMutableDictionary alloc]init];
NSArray *cityName=[[NSArray alloc]init];
NSArray *townName=[[NSArray alloc]init];
NSArray *taxis=[[NSArray alloc]init];
NSArray *ids=[[NSArray alloc]init];
for (int i=0; i<json.count; i++)
{
//cityName=[[NSMutableArray alloc] initWithCapacity:json.count];
ids = [[json objectAtIndex:i] objectForKey:#"id"];
cityName = [[json objectAtIndex:i] objectForKey:#"cityName"];
townName=[[json objectAtIndex:i] objectForKey:#"townName"];
taxis=[[json objectAtIndex:i] objectForKey:#"taxis"];
NSMutableArray *taxisArray=[[NSMutableArray alloc] initWithObjects:taxis,nil];
NSMutableDictionary *towensdict=[[ NSMutableDictionary alloc] initWithObjectsAndKeys:taxisArray,townName, nil];
NSMutableDictionary *cities1=[[NSMutableDictionary alloc] initWithObjectsAndKeys:towensdict,cityName, nil];
NSLOG (#"%#", cities1) here, gives me the print out above
[dictArray addEntriesFromDictionary:cities1 ];
Then I tried Jdodgers solution as follows;
NSMutableDictionary *combinedDictionary = [[NSMutableDictionary alloc] init];
for (NSDictionary *currentDictionary in dictArray) {
NSArray *keys = [currentDictionary allKeys];
for (int n=0;n<[keys count];n++) {
NSMutableDictionary *dictionaryToAdd = [combinedDictionary valueForKey:[keys objectAtIndex:n]];
if (!dictionaryToAdd) dictionaryToAdd = [[NSMutableDictionary alloc] init];
[dictionaryToAdd setValuesForKeysWithDictionary:[currentDictionary valueForKey:[keys objectAtIndex:n]]];
[combinedDictionary setValue:dictionaryToAdd forKey:[keys objectAtIndex:n]];
NSLog(#"%#", currentDictionary);
}
}
//this gives error "unrecognized selector sent to instance", here is the print out
combinedDictionary NSMutableDictionary * 0x000000010012e580
currentDictionary NSDictionary *const 0x0000000100116460
dictArray NSMutableDictionary * 0x000000010012e220
[0] key/value pair
key id 0x0000000100116460
[0] id
value id 0x000000010012e440
[0] id
keys NSArray * 0x0000000000000000
You could create an NSMutableDictionary and loop through your array, adding the keys to the mutable dictionary using the allKeys.
For example, if your array was called dictArray, you could do:
NSMutableDictionary *combinedDictionary = [[NSMutableDictionary alloc] init];
for (NSDictionary *currentDictionary in dictArray) {
NSArray *keys = [currentDictionary allKeys];
for (int n=0;n<[keys count];n++) {
NSMutableDictionary *dictionaryToAdd = [combinedDictionary valueForKey:[keys objectAtIndex:n]];
if (!dictionaryToAdd) dictionaryToAdd = [[NSMutableDictionary alloc] init];
[dictionaryToAdd setValuesForKeysWithDictionary:[currentDictionary valueForKey:[keys objectAtIndex:n]]];
[combinedDictionary setValue:dictionaryToAdd forKey:[keys objectAtIndex:n]];
}
}
This code first creates a dictionary combinedDictionary that will be your final dictionary. It loops through all of the dictionaries in your array and for each one does the following:
First, it gets an array of all keys in the dictionary. For the dictionaries you provided this array will look like #[#"Bath"] for the first 3 and #[#"Birmingam"] for the other two.
The code then loops through these keys and gets the already existing dictionary from the combined dictionary from this key. If the dictionary doesn't exist, one is created.
Then, it adds all of the values from the dictionary from the array and sets the new dictionary to be the one in combinedDictionary.
For C I would init an array like this:
NSInteger x[3][10]; That works.
Below I have a one dim array that works. Would like to move all of this to a 2 dim array, How do I init it? So in other words take the code below and make it work with 2 dimensions.
NSMutableArray *SRData;
SRData = [[NSMutableArray alloc] init];
NSMutableDictionary *SRRow;
SRRow = [[NSMutableDictionary alloc] init];
[SRRow setObject:#"Read" forKey:#"Descr"];
[SRRow setObject:#"Read2.png" forKey:#"Img"];
[SRRow setObject:#"Read the codes" forKey:#"Det"];
[SRData addObject:SRRow] ;
[SRRow release];
In Objective-C, you just have to have an array of arrays to get the second dimension. To my knowledge, there is no shorthand, so you're stuck doing something like the following:
NSMutableArray *firstDimension = [[NSMutableArray alloc] init];
for (int i = 0; i < rows; i++)
{
NSMutableArray *secondDimension = [[NSMutableArray alloc] init];
[firstDimension addObject:secondDimension];
}
So all you would do is add your other objects (in your case, the NSMutableDictionarys) to the secondDimension array. Usage would be like:
[[firstDimension objectAtIndex:0] objectAtIndex:0];
Edit
Full code example:
NSMutableArray *SRData = [[NSMutableArray alloc] init]; //first dimension
NSMutableArray *SRRow = [[NSMutableArray alloc] init]; //second dimension
[SRData addObject:SRRow]; //add row to data
[SRRow release];
NSMutableDictionary *SRField = [[NSMutableDictionary alloc] init]; //an element of the second dimension
[SRField setObject:#"Read" forKey:#"Descr"];
//Set the rest of your objects
[SRRow addObject:SRField]; //Add field to second dimension
[SRField release];
Now, to get at that "field" you would use code such as the following:
[[SRData objectAtIndex:0] objectAtIndex:0]; //Get the first element in the first array (the second dimension)
I have model class which contains NSString's- studentName, studentRank and studentImage. I wanna sort the NSMutableArray according to studentRanks. what I have done is
- (void)uploadFinished:(ASIHTTPRequest *)theRequest
{
NSString *response = nil;
response = [formDataRequest responseString];
NSError *jsonError = nil;
SBJsonParser *json = [[SBJsonParser new] autorelease];
NSArray *arrResponse = (NSArray *)[json objectWithString:response error:&jsonError];
if ([jsonError code]==0) {
// get the array of "results" from the feed and cast to NSArray
NSMutableArray *localObjects = [[[NSMutableArray alloc] init] autorelease];
// loop over all the results objects and print their names
int ndx;
for (ndx = 0; ndx < arrResponse.count; ndx++)
{
[localObjects addObject:(NSDictionary *)[arrResponse objectAtIndex:ndx]];
}
for (int x=0; x<[localObjects count]; x++)
{
TopStudents *object = [[[TopStudents alloc] initWithjsonResultDictionary:[localObjects objectAtIndex:x]] autorelease];
[localObjects replaceObjectAtIndex:x withObject:object];
}
topStudentsArray = [[NSMutableArray alloc] initWithArray:localObjects];
}
}
How can I sort this topStudentsArray according to the ranks scored by the Students and If the two or more student have the same rank, How can I group them.
I did like this
TopStudents *object;
NSSortDescriptor * sortByRank = [[[NSSortDescriptor alloc] initWithKey:#"studentRank" ascending:NO] autorelease];
NSArray * descriptors = [NSArray arrayWithObject:sortByRank];
NSArray * sorted = [topStudentsArray sortedArrayUsingDescriptors:descriptors];
but this is not displaying results properly. please help me to overcome this problem. thanks in advance.
doing something like this might do the trick
Initially sort the arrGroupedStudents in the (ascending/descending) order of studentRank
//Create an array to hold groups
NSMutableArray* arrGroupedStudents = [[NSMutableArray alloc] initWithCapacity:[topStudentsArray count]];
for (int i = 0; i < [topStudentsArray count]; i++)
{
//Grab first student
TopStudents* firstStudent = [topStudentsArray objectAtIndex:i];
//Create an array and add first student in this array
NSMutableArray* currentGroupArray = [[[NSMutableArray alloc] initWithCapacity:0] autorelease];
[currentGroupArray addObject:firstStudent];
//create a Flag and set to NO
BOOL flag = NO;
for (int j = i+1; j < [topStudentsArray count]; j++)
{
//Grab next student
TopStudents* nextStudent = [topStudentsArray objectAtIndex:j];
//Compare the ranks
if ([firstStudent.studentRank intValue] == [nextStudent.studentRank intValue])
{
//if they match add this to same group
[currentGroupArray addObject:nextStudent];
}
else {
//we have got our group so stop next iterations
[arrGroupedStudents addObject:currentGroupArray];
// We will assign j-1 to i
i=j-1;
flag = YES;
break;
}
}
//if entire array has students with same rank we need to add it to grouped array in the end
if (!flag) {
[arrGroupedStudents addObject:currentGroupArray];
}
}
Finally your arrGroupedStudents will contain grouped array with equal rank. I have not test run the code so you might need to fix a few things falling out of place. Hope it helps
If you want to display in the order of ranks, you should set the ascending as YES.
NSSortDescriptor * sortByRank = [[NSSortDescriptor alloc] initWithKey:#"studentRank" ascending:YES];
static int mySortFunc(NSDictionary *dico1, NSDictionary *dico2, void *context)
{
NSString *studentName1 = [dico1 objectForKey:#"studentName"];
NSString *studentName2 = [dico2 objectForKey:#"studentName"];
return [studentName1 compare:studentName2];
}
- (IBAction)sortBtnTouched:(id)sender
{
[topStudentsArray sortUsingFunction:mySortFunc context:NULL];
}
I have a table view, which has its data source from an array that contains names of people.
Now to make it easy to find people, I want to section the table view so that it has the letter A-Z on the right hand side, just like the Address Book app.
But my current array just contains a collection of NSStrings. How do I split them so that they are grouped by the first letter of the names? Is there any convenient way to do it?
EDIT: If anyone's interested in my final code:
NSMutableArray *arrayChars = [[NSMutableArray alloc] init];
for (char i = 'A'; i <= 'Z' ; i++) {
NSMutableDictionary *characterDict = [[NSMutableDictionary alloc]init];
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
for (int k = 0; k < [myList count]; k++) {
NSString *currentName = [[friends objectAtIndex:k] objectForKey:#"name"];
char heading = [currentName characterAtIndex:0];
heading = toupper(heading);
if (heading == i) {
[tempArray addObject:[friends objectAtIndex:k]];
}
}
[characterDict setObject:tempArray forKey:#"rowValues"];
[characterDict setObject:[NSString stringWithFormat:#"%c",i] forKey:#"headerTitle"];
[arrayChars addObject:characterDict];
[characterDict release];
[tempArray release];
}
At the end of the function I'll have:
arrayChars [0] = dictionary(headerTitle = 'A', rowValues = {"adam", "alice", etc})
arrayChars[1] = dictionary(headerTitle = 'B', rowValues = {"Bob", etc})
Thank you everyone for your help!
You can use a dictionary to sort them, so create an array with all the letters you want to sort and a array with nil objects to initialize the dictionary
NSArray *names = #[#"javier",#"juan", #"pedro", #"juan", #"diego"];
NSArray *letters = #[#"j", #"p", #"d"];
NSMutableArray *objects = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < [letters count]; ++i)
{
[objects addObject:[[NSMutableArray alloc] init]];
}
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:letters];
Then you must find the first letter if the word and put that word into the corresponding key in the dictionary
for (NSString *name in names) {
NSString *firstLetter = [name substringToIndex:1];
for (NSString *letter in letters) {
if ([firstLetter isEqualToString:letter]) {
NSMutableArray *currentObjects = [dictionary objectForKey:letter];
[currentObjects addObject:name];
}
}
}
To check you can print directly the dictionary
NSLog(#"%#", dictionary);
Then is your work to fill your sections in the tableview using the dictionary
Here are two methods that return a dictionary of my custom four-propery objects. They make arrays of strings, floats and BOOLs to put in the Chemical objects, then build a dictionary from the arrays. I'm new enough to the whole memory management game that I'm not always sure when I own something and when to release it. I'm making all kinds of strings on the fly.
Here's the thing: The static analyzer sees no problem with the first method, - (id)generateChlorineDictionary but says there's a leak in the second one, - (id)generateCYADictionary. It says it starts at the NSMutableArray *cyaGranulesArray... and then goes to NSDictionary *cyaDictionary... and finally to the return cyaDictionary statement.
Here are the two methods; sorry they're so long!
EDIT: Changed name from generateChlorineDictionary to newChlorineDictionary
Removed a release that happened after the return
- (id)newChlorineDictionary {
// Sets up the array for the Bleach key
NSMutableArray *bleachArray = [[NSMutableArray alloc] init];
NSArray *bleachConcentrationArray = [[NSArray alloc] initWithObjects:#"6%", #"10%", #"12%", nil];
float bleachConstantArray[] = {0.0021400, 0.0012840, 0.0010700};
for (int i=0; i<3; i++) {
Chemical *bleachChemical = [[Chemical alloc] initWithChemical:#"Bleach"
andConcentration:[bleachConcentrationArray objectAtIndex:i]
andConstant:bleachConstantArray[i]
andIsLiquid:YES];
[bleachArray addObject:bleachChemical];
NSLog(#"bleachChemical: chemName = %#, chemConcentration = %#, chemConstant = %1.6f, chemIsLiquid = %d", bleachChemical.chemName, bleachChemical.chemConcentration, bleachChemical.chemConstant, bleachChemical.chemIsLiquid);
[bleachChemical release];
}
bleachConcentrationArray = nil;
// Sets up the array for the Trichlor key
NSMutableArray *trichlorArray = [[NSMutableArray alloc] init];
Chemical *trichlorChemical = [[Chemical alloc] initWithChemical:#"Trichlor"
andConcentration:#"90%"
andConstant:0.0001480
andIsLiquid:NO];
[trichlorArray addObject:trichlorChemical];
NSLog(#"trichlorChemical: chemName = %#, chemConcentration = %#, chemConstant = %1.6f, chemIsLiquid = %d", trichlorChemical.chemName, trichlorChemical.chemConcentration, trichlorChemical.chemConstant, trichlorChemical.chemIsLiquid);
[trichlorChemical release];
// Sets up the array for the Dichlor key
NSMutableArray *dichlorArray = [[NSMutableArray alloc] init];
NSArray *dichlorConcentrationArray = [[NSArray alloc] initWithObjects:#"56%", #"62%", nil];
float dichlorConstantArray[] = {0.0002400, 0.0002168};
for (int i=0; i<2; i++) {
Chemical *dichlorChemical = [[Chemical alloc] initWithChemical:#"Dichlor"
andConcentration:[dichlorConcentrationArray objectAtIndex:i]
andConstant:dichlorConstantArray[i]
andIsLiquid:NO];
[dichlorArray addObject:dichlorChemical];
NSLog(#"dichlorChemical: chemName = %#, chemConcentration = %#, chemConstant = %1.6f, chemIsLiquid = %d", dichlorChemical.chemName, dichlorChemical.chemConcentration, dichlorChemical.chemConstant, dichlorChemical.chemIsLiquid);
[dichlorChemical release];
}
dichlorConcentrationArray = nil;
// Sets up the array for the Cal Hypo key
NSMutableArray *calHypoArray = [[NSMutableArray alloc] init];
NSArray *calHypoConcentrationArray = [[NSArray alloc] initWithObjects:#"48%", #"53%", #"65", #"73", nil];
float calHypoConstantArray[] = {0.0002817, 0.0002551, 0.0002080, 0.0001852};
for (int i=0; i<2; i++) {
Chemical *calHypoChemical = [[Chemical alloc] initWithChemical:#"Cal Hypo"
andConcentration:[calHypoConcentrationArray objectAtIndex:i]
andConstant:calHypoConstantArray[i]
andIsLiquid:NO];
[calHypoArray addObject:calHypoChemical];
NSLog(#"calHypoChemical: chemName = %#, chemConcentration = %#, chemConstant = %1.6f, chemIsLiquid = %d", calHypoChemical.chemName, calHypoChemical.chemConcentration, calHypoChemical.chemConstant, calHypoChemical.chemIsLiquid);
[calHypoChemical release];
}
calHypoConcentrationArray = nil;
// Sets up the array for the Li Hypo key
NSMutableArray *liHypoArray = [[NSMutableArray alloc] init];
Chemical *liHypoChemical = [[Chemical alloc] initWithChemical:#"Li Hypo"
andConcentration:#"90%"
andConstant:0.0003800
andIsLiquid:NO];
[liHypoArray addObject:liHypoChemical];
NSLog(#"liHypoChemical: chemName = %#, chemConcentration = %#, chemConstant = %1.6f, chemIsLiquid = %d", liHypoChemical.chemName, liHypoChemical.chemConcentration, liHypoChemical.chemConstant, liHypoChemical.chemIsLiquid);
[liHypoChemical release];
// The array of keys for the chlorine chemicals
NSArray *chlorineKeys = [[NSArray alloc] initWithObjects:#"Bleach", #"Trichlor", #"Dichlor", #"Cal Hypo", #"Li Hypo", nil];
// The array of values for the chlorine chemicals
NSArray *chlorineValues = [[NSArray alloc] initWithObjects:bleachArray, trichlorArray, dichlorArray, calHypoArray, liHypoArray, nil];
[bleachArray release];
[trichlorArray release];
[dichlorArray release];
[calHypoArray release];
[liHypoArray release];
// The dictionary to hold the arrays of chlorine chemical objects
NSDictionary *chlorineDictionary = [[NSDictionary alloc] initWithObjects:chlorineValues forKeys:chlorineKeys];
[chlorineValues release];
[chlorineKeys release];
return chlorineDictionary;
}
EDIT: Changed name from generateCYADictionary to newCYADictionary
Removed a release that happened after the return
- (id)newCYADictionary {
// Sets up the array for the CYA Granules key
NSMutableArray *cyaGranulesArray = [[NSMutableArray alloc] init];
Chemical *cyaGranulesChemical = [[Chemical alloc] initWithChemical:#"CYA Granules"
andConcentration:#""
andConstant:0.0001330
andIsLiquid:NO];
[cyaGranulesArray addObject:cyaGranulesChemical];
NSLog(#"cyaGranulesChemical: chemName = %#, chemConcentration = %#, chemConstant = %1.6f, chemIsLiquid = %d", cyaGranulesChemical.chemName, cyaGranulesChemical.chemConcentration, cyaGranulesChemical.chemConstant, cyaGranulesChemical.chemIsLiquid);
[cyaGranulesChemical release];
// Sets up the array for the Liquid Stabilizer key
NSMutableArray *liquidStabilizerArray = [[NSMutableArray alloc] init];
Chemical *liquidStabilizerChemical = [[Chemical alloc] initWithChemical:#"Liquid Stabilizer"
andConcentration:#""
andConstant:0.0003460
andIsLiquid:YES];
[liquidStabilizerArray addObject:liquidStabilizerChemical];
NSLog(#"liquidStabilizerChemical: chemName = %#, chemConcentration = %#, chemConstant = %1.6f, chemIsLiquid = %d", liquidStabilizerChemical.chemName, liquidStabilizerChemical.chemConcentration, liquidStabilizerChemical.chemConstant, liquidStabilizerChemical.chemIsLiquid);
[liquidStabilizerChemical release];
// The array of keys for the CYA chemicals
NSArray *cyaKeys = [[NSArray alloc] initWithObjects:#"CYA Granules", #"Liquid Stabilizer", nil];
// The array of values for the CYA chemicals
NSArray *cyaValues = [[NSArray alloc] initWithObjects:cyaGranulesArray, liquidStabilizerArray, nil];
[cyaGranulesArray release];
[liquidStabilizerArray release];
// The dictionary to hold the arrays of CYA chemical objects
NSDictionary *cyaDictionary = [[NSDictionary alloc] initWithObjects:cyaValues forKeys:cyaKeys];
[cyaKeys release];
[cyaValues release];
return cyaDictionary;
}
Replace the
return cyaDictionary;
[cyaDictionary release];
With
return [cyaDictionary autorelease];
Or, you might replace the
NSDictionary *chlorineDictionary = [[NSDictionary alloc] initWithObjects:chlorineValues forKeys:chlorineKeys];
With
NSDictionary *chlorineDictionary = [NSDictionary dictionaryWithObjects:chlorineValues forKeys:chlorineKeys];
Instead of adding the autorelease.
In your original implementation the [cyaDictionary release]; is never executed (because it is after return).
You can use this dictionary outside this method and you shouldn't release it there.
You might want also return a retained object (without the autorelease) and release it outside the method. In this case you should start the method name with "new" or "alloc"...
EDIT (Important):
You should use only one of my suggestions.
Use the autorelease in the return line
Use the dictionaryWith...
Add the "new" or "alloc" prefix in the method name and release the returned object outside this method.
If you replace the alloc init with dictionaryWith... then you get an autoreleased object. And then, if you release it in the outer method then you have a serious problem (the object will try to release itself after the current runloop of the thread and it may crash the app because the object will already be released by you).
EDIT (due to one of the comments)
If you want to create a property that will return a dictionary:
// MyClass.h file
#interface MyClass : NSObject {
..
NSDictionary *_dict1;
..
}
#property (nonatomic, retain) NSDictionary *dict1;
..
#end
// MyClass.m file
#implementation MyClass
#synthesize dict1 = _dict1;
..
- (NSDictionary *)dict1 {
if (_dict1 == nil) {
NSDictionary *dict1Temp = [NSDictionary new];
// Your implementation goes here...
self.dict1 = dict1Temp;
[dict1Temp release];
}
}
..
- (void)dealloc {
[_dict1 release];
[suoer dealloc];
}
#end