In my Xcode Project (Objective-C), i store json Result in a NSMutableDictionary, but the result is in false order direction.
How can i sort a NSMutableDictionary is ASC order on Objective-C.
Here is my NSMutableDictionary:
{
3 = (
11,
12,
13,
14,
15,
16,
17,
18,
19,
20
);
2 = (
2,
3,
4,
5,
6,
7,
8,
9,
10
);
1 = (
0,
1
);
4 = (
21,
22,
23,
24,
25,
26
);
}
I expect a sort order 1,2,3,4 for UITableView Section.
#rmaddy is right,the following is the implementation code, very simple.
- (NSMutableArray *)sortDictionary:(NSMutableDictionary *)dictionary {
NSArray *sortedKeys = [[dictionary allKeys] sortedArrayUsingSelector:#selector(compare:)];
NSMutableArray *sortedArray = [NSMutableArray arrayWithCapacity:sortedKeys.count];
for (NSString *key in sortedKeys) {
[sortedArray addObject:[dictionary objectForKey:key]];
}
return sortedArray;
}
example
NSDictionary *dict = #{#"3":#{#"3333":#"3333"},
#"2":#{#"2222":#"2222"},
#"1":#{#"1111":#"1111"},
#"4":#{#"4444":#"444"}};
[self sortDictionary:dict];
result:
sortedArray :(
{
1111 = 1111;
},
{
2222 = 2222;
},
{
3333 = 3333;
},
{
4444 = 444;
}
)
I have an objective C object 'Obj' with an
#property (strong, nonatomic) NSMutableDictionary *obj;
This gets populated with data from an api in following format.
{
0 = ( 0, "7.00", "8.59”, ”15.00”, ”16.59", "19.00", "20.59 );
1 = ( 1, "7.00", "8.59”, ”15.00”, ”16.59", "19.00", "20.59 );
2 = ( 2, "7.00", "8.59”, ”15.00”, ”16.59", "19.00", "20.59 );
3 = ( 3, "7.00", "8.59”, ”15.00”, ”16.59", "19.00", "20.59 );
4 = ( 4, "7.00", "8.59”, ”15.00”, ”16.59", "19.00", "20.59 );
5 = ( 5, "7.00", "8.59”, ”15.00”, ”16.59", "19.00", "20.59 );
6 = ( 6, "7.00", "8.59”, ”15.00”, ”16.59", "19.00", "20.59 );
}
I need to parse the data and send it back as an array in following format.
`{
[ 0, 7, 00, 8, 59 ],
[0, 15, 00, 16, 59] ,
[0, 19, 00, 20, 59] ,
[ 1, 7, 00, 8, 59 ],
[1, 15, 00, 16, 59] ,
[1, 19, 00, 20, 59],
……
……
[ 6, 7, 00, 8, 59 ],
[6, 15, 00, 16, 59] ,
[6, 19, 00, 20, 59]
}`
Where 0,1,2,3,4,5,6 are days and rest of the information is hours and mins. so for each slot, the format is
`[day, from_hour, from_min, to_hour, to_min],
[0, 7, 0, 8, 59],`
A day could have multiple slots or just one slot.
So far I manage to run a loop and separate each day's record as below.
NSMutableArray *elementArray =[[NSMutableArray alloc ]init];
NSMutableArray *results =[[NSMutableArray alloc ]init];
NSInteger starthour = 0 ;
NSInteger startmin = 0 ;
NSInteger endhour = 0 ;
NSInteger endmin = 0 ;
NSMutableArray *temp = [[NSMutableArray alloc]init];
NSString *string;
int i = 0;
for ( i = 0; i <=6; i ++){
string = [NSString stringWithFormat:#"%d",i];
elementArray =[Obj.obj valueForKey:string];
starthour = [[elementArray objectAtIndex:1]integerValue];
startmin =([[elementArray objectAtIndex:1]floatValue]-[[elementArray objectAtIndex:1]integerValue])*100;
endhour = [[elementArray objectAtIndex:2]integerValue];
endmin =([[elementArray objectAtIndex:2]floatValue]-[[elementArray objectAtIndex:2]integerValue])*100;
NSNumber *day = [NSNumber numberWithInteger:[string integerValue]];
NSNumber *starthour1 = [NSNumber numberWithInteger:(int)starthour];
NSNumber *startmin1 = [NSNumber numberWithInteger:(int)startmin];
NSNumber *endhour1 = [NSNumber numberWithInteger:(int)endhour];
NSNumber *endmin1 = [NSNumber numberWithInteger:(int)endmin];
[temp addObject:day];
[temp addObject:starthour1];
[temp addObject:startmin1];
[temp addObject:endhour1];
[temp addObject:endmin1];
[results addObject:temp];
}
This gives me access to each record. My thought process is saying I could solve this by going through each record and populating the required array as, 'i' being the day, then running a nest loop on each record and extracting hours and mins?
You don't say what your problem actually is, i.e. you started on a solution and stopped and turned to SO, why?
Let's see if we can help you along with some pseudo-code.
You have a dictionary of arrays. the keys represent day numbers as do the first element of each array. After the first array element the elements come in pairs, each is a string containing a textual representation of hours and minutes separated by a full stop. You want and array of arrays where each element has 5 members: day number, start hour, start min, end hour, end minute, all as numbers.
A basic algorithm to handle this is two nested loops. You need somewhere to store the result:
results <- new empty array
Now you need to iterate over your dictionary:
for every key in sourceDictionary
elementArray = sourceDictionary[key]
[This is the loop you've written, except you generated the keys and looked them up while here we extract the keys from the dictionary. If you wish to process the keys in a particular order then generating them in that order, or extracting and sorting them, will handle that.]
Now you'd better do some data validation, elementArray should have at least the day number and one pair of strings in it, test for that:
check elementArray count > 1 and odd else handle error
Now you need to process each pair of strings, first access them:
cursor <- 1 // element 0 is the repeated day number
while cursor < elementArray count do
startTime <- elementArray[cursor]
endTime <- elementArray[cursor+1]
cursor <- cursor + 2 // ready for next iteration
So now you have the day number, key, and the start and end times as string, startTime & endTime. Now you need to split your time strings at the full stop, returning an array of substrings:
startParts <- startTime split at "."
More checks, did you get two parts?
check startParts count is 2 else handle error
Now convert each substring to an integer:
startHours <- parse startParts[0] as integer
startMins <- parse startParts[1] as integer
And keep checking:
check startHours in [0, 23] and startMins in [0, 59] else handle error
You've now got the five values you want, add them to your results array:
results <- results append array of (key, startHours, startMins, endHours, endMins)
Now just convert that to Objective-C and fill in the details. The first loop could be a for in one, the second a for(init; test; increment) one. For splitting a string look at NSString's methods, one will fit the bill. For parsing there are multiple options including NSString methods.
HTH
I got it working with desired output, but code looks messy, could be made elegant.
` NSMutableArray *elementArray =[[NSMutableArray alloc ]init];
NSMutableArray *results =[[NSMutableArray alloc ]init];
NSInteger starthour = 0 ;
NSInteger startmin = 0 ;
NSInteger endhour = 0 ;
NSInteger endmin = 0 ;
NSNumber *starthour1 ;
NSNumber *startmin1 ;
NSNumber *endhour1 ;
NSNumber *endmin1 ;
NSMutableArray *temp = [[NSMutableArray alloc]init];
NSString *string;
int i = 0;
for ( i = 0; i <=6; i ++){
string = [NSString stringWithFormat:#"%d",i];
elementArray =[Obj.obj valueForKey:string];
starthour = [[elementArray objectAtIndex:1]integerValue];
startmin =([[elementArray objectAtIndex:1]floatValue]-[[elementArray objectAtIndex:1]integerValue])*100;
endhour = [[elementArray objectAtIndex:2]integerValue];
endmin =([[elementArray objectAtIndex:2]floatValue]-[[elementArray objectAtIndex:2]integerValue])*100;
NSNumber *day = [NSNumber numberWithInteger:[string integerValue]];
starthour1 = [NSNumber numberWithInteger:(int)starthour];
startmin1 = [NSNumber numberWithInteger:(int)startmin];
endhour1 = [NSNumber numberWithInteger:(int)endhour];
endmin1 = [NSNumber numberWithInteger:(int)endmin];
[temp addObject:day];
[temp addObject:starthour1];
[temp addObject:startmin1];
[temp addObject:endhour1];
[temp addObject:endmin1];
[results addObject:[temp copy]];
[temp removeAllObjects];
starthour = [[elementArray objectAtIndex:3]integerValue];
startmin =([[elementArray objectAtIndex:3]floatValue]-[[elementArray objectAtIndex:3]integerValue])*100;
endhour = [[elementArray objectAtIndex:4]integerValue];
endmin =([[elementArray objectAtIndex:4]floatValue]-[[elementArray objectAtIndex:4]integerValue])*100;
starthour1 = [NSNumber numberWithInteger:(int)starthour];
startmin1 = [NSNumber numberWithInteger:(int)startmin];
endhour1 = [NSNumber numberWithInteger:(int)endhour];
endmin1 = [NSNumber numberWithInteger:(int)endmin];
[temp addObject:day];
[temp addObject:starthour1];
[temp addObject:startmin1];
[temp addObject:endhour1];
[temp addObject:endmin1];
[results addObject:[temp copy]];
[temp removeAllObjects];
starthour = [[elementArray objectAtIndex:5]integerValue];
startmin =([[elementArray objectAtIndex:5]floatValue]-[[elementArray objectAtIndex:5]integerValue])*100;
endhour = [[elementArray objectAtIndex:6]integerValue];
endmin =([[elementArray objectAtIndex:6]floatValue]-[[elementArray objectAtIndex:6]integerValue])*100;
starthour1 = [NSNumber numberWithInteger:(int)starthour];
startmin1 = [NSNumber numberWithInteger:(int)startmin];
endhour1 = [NSNumber numberWithInteger:(int)endhour];
endmin1 = [NSNumber numberWithInteger:(int)endmin];
[temp addObject:day];
[temp addObject:starthour1];
[temp addObject:startmin1];
[temp addObject:endhour1];
[temp addObject:endmin1];
[results addObject:[temp copy]];
[temp removeAllObjects];
`
The output is what I wanted looks like below.
(
(
0,
7,
0,
8,
59
),
(
0,
15,
0,
16,
59
),
(
0,
19,
0,
20,
59
),
(
1,
7,
0,
8,
59
),
(
1,
15,
0,
16,
59
),
(
1,
22,
0,
23,
59
),
(
2,
7,
0,
8,
59
),
(
2,
15,
0,
16,
59
),
(
2,
19,
0,
20,
59
),
(
3,
7,
0,
8,
59
),
(
3,
15,
0,
16,
59
),
(
3,
22,
0,
23,
59
),
(
4,
7,
0,
8,
59
),
(
4,
15,
0,
16,
59
),
(
4,
19,
0,
20,
59
),
(
5,
7,
0,
8,
59
),
(
5,
15,
0,
16,
59
),
(
5,
22,
0,
23,
59
),
(
6,
7,
0,
8,
59
),
(
6,
15,
0,
16,
59
),
(
6,
19,
0,
20,
59
)
)
I have two NSArray. They are myArray & alphabets. myArray have some value and alphabets have the list of all alphabets.
I also have a NSMutableDictionary which is called finalDic. Where I want to add myArray values according to it's first latter where the first latter will be it's key. For doing that I add an extra NSMutableArray called objArray. Below is my code.
myArray = [[NSArray alloc] initWithObjects:
#"Bangladesh",
#"France",
#"Italy",
#"Canada",
#"Austria",
#"Germany",
#"Bolivia",
#"Argentina",
#"England", nil];
NSArray *alphabets = [[NSArray alloc] initWithObjects:#"A", #"B", #"C", #"D", #"E", #"F", #"G", #"H", #"I", #"J", #"K", #"L", #"M", #"N", #"O", #"P", #"Q", #"R", #"S", #"T", #"U", #"V", #"W", #"X", #"Y", #"Z", nil];
NSMutableDictionary *finalDic = [[NSMutableDictionary alloc] init];
NSMutableArray *objArray = [[NSMutableArray alloc] init];
int i;
int k;
for (i = 0; i < [alphabets count]; i++)
{
NSString *alp = [alphabets objectAtIndex:i];
for (k = 0; k < [myArray count]; k++)
{
NSString *vlu = [myArray objectAtIndex:k];
if([[myArray objectAtIndex:k] hasPrefix:[alphabets objectAtIndex:i]])
{
[objArray addObject:[myArray objectAtIndex:k]];
}
}
if (objArray != nil)
{
[finalDic setObject:objArray forKey:[alphabets objectAtIndex:i]];
[objArray removeAllObjects];
}
}
NSLog(#"finalDic %#", finalDic);
The problem is I am not getting the accurate result. I am getting this NSLog :
finalDic {
A = (
);
B = (
);
C = (
);
D = (
);
E = (
);
F = (
);
G = (
);
H = (
);
I = (
);
J = (
);
K = (
);
L = (
);
M = (
);
N = (
);
O = (
);
P = (
);
Q = (
);
R = (
);
S = (
);
T = (
);
U = (
);
V = (
);
W = (
);
X = (
);
Y = (
);
Z = (
);
}
I debug the code and seen that after adding first key and it's value (which is objArray) the first key and value getting empty!, just before beginning 2nd for loop for B. Don't know why? Am I missing something?
Please reply if you understand my problem. A lot of thanks in advance.
if you step through it you will see that your finalDic is good until [objArray removeAllObjects];
FinalDic is pointing to objArray. You need to write create a temporary object or write this differently.
I am migrating from an old version (v2) to the new version (v3) of my app and by that adding two new fields for each player into the playerdata.plist. The reason why i am putting '99' in the new fields is only for testing as i am testing on a v3 file, with the extra fields, to make it easier.
What i am trying to accomplish is:
a. read the file with the player data
b. add to new fields
c. store the file
The current result is that i am storing the same data for each players after the migration.
Code:
- (void)migratePlayerDataPlist {
//====THIS PIECE OF CODE SHOULD BE REMOVED AFTER CERTAIN TIME AS IT WILL NOT BE NEEDED====//
//====..WHEN ALL OLD USERS HAVE MIGRATED. THIS IS WRITTEN SEPTEMBER 5 2012 VERSION 3.0====//
// This procedure migrates the old playerdatafile to version 3 of the game
//Prepare File Manager
NSString *filePath = [self dataFilePath];
NSFileManager *fileMgr;
fileMgr = [NSFileManager defaultManager];
if ([fileMgr fileExistsAtPath: filePath] == YES) {
dataArray = [[NSMutableArray alloc]init];
NSMutableDictionary *gameFileDict = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
NSLog(#"gameFileDict: %#", gameFileDict);
myKeyArray = [gameFileDict allKeys];
int nrOfKeys = [myKeyArray count];
NSMutableDictionary *migrationDict = [[NSMutableDictionary alloc]initWithCapacity:200];
NSMutableDictionary *xmigrationDict = [[NSMutableDictionary alloc]initWithCapacity:200];
NSLog(#"nrOfKeys: %i", nrOfKeys);
for (int oo = 0; oo < nrOfKeys; oo++) {
[dataArray removeAllObjects]; // Clean array
theObjects = [gameFileDict valueForKey:[myKeyArray objectAtIndex:oo]];
[dataArray addObject:[theObjects objectAtIndex:0]]; // diffSelection
[dataArray addObject:[theObjects objectAtIndex:1]]; // # of games played
[dataArray addObject:[theObjects objectAtIndex:2]]; // # correct answers
[dataArray addObject:[theObjects objectAtIndex:3]]; // # questions
[dataArray addObject:[NSNumber numberWithInt:99]]; // >>New field<< # of games won
[dataArray addObject:[NSNumber numberWithInt:99]]; // >>New field<< # of games lost
xmigrationDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:dataArray, [myKeyArray objectAtIndex:oo], nil];
[migrationDict addEntriesFromDictionary:xmigrationDict];
}
NSLog(#"xmigrationDict: %#", xmigrationDict);
NSLog(#"migrationDict: %#", migrationDict);
NSLog(#"theObjects: %#", theObjects);
// Delete the old file
[fileMgr removeItemAtPath:filePath error:NULL];
// Resave the file with the new data
[migrationDict writeToFile:filePath atomically: TRUE];
// ...and the migration is done
}
}
Current NSLog-based output:
2012-09-06 20:57:50.332 xxxx_3[1505:fb03] gameFileDict: {
Barnspelare = (
1,
1,
2,
2,
1,
0
);
"Ton\U00e5rsspelare" = (
2,
0,
0,
0,
0,
0
);
Vuxenspelare = (
3,
1,
0,
2,
0,
1
);
}
2012-09-06 20:57:50.334 xxxx_3[1505:fb03] nrOfKeys: 3
2012-09-06 20:57:50.335 xxxx_3[1505:fb03] xmigrationDict: {
"Ton\U00e5rsspelare" = (
2,
0,
0,
0,
99,
99
);
}
2012-09-06 20:57:50.336 xxxx_3[1505:fb03] migrationDict: {
Barnspelare = (
2,
0,
0,
0,
99,
99
);
"Ton\U00e5rsspelare" = (
2,
0,
0,
0,
99,
99
);
Vuxenspelare = (
2,
0,
0,
0,
99,
99
);
}
2012-09-06 20:57:50.336 xxxx_3[1505:fb03] theObjects: (
2,
0,
0,
0,
0,
0
)
I think that there is a simpler approach to this. Here is a way:
(Assuming that you have fetched your data in a dictionary called d and skipping the parts where you read / write the file...)
NSMutableDictionary *md = [d mutableCopy];
for (NSString *key in d)
{
NSMutableArray *values = [[md valueForKey:key] mutableCopy];
[values addObject:[NSNumber numberWithInt:99]]; // 1st new field
[values addObject:[NSNumber numberWithInt:99]]; // 2nd new field
[md setObject:values forKey:key];
}
And now your new dictionary (the md) contains:
{
Barnspelare = (
1,
1,
2,
2,
1,
0,
99,
99
);
"Ton\U00e5rsspelare" = (
2,
0,
0,
0,
0,
0,
99,
99
);
Vuxenspelare = (
3,
1,
0,
2,
0,
1,
99,
99
);
}