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 am updating a database table before requesting some json data from a web service. Some times response fail. If this type of occasion ho can i rollback update operation using objectivec.
-(void)syncPhoneDBWithData:(NSData *)data{
NSDictionary *dictionary = [NSDictionary dictionaryWithJSONData:data];
if ([dictionary count]!= 0) {
NSArray *ticketsArray = [dictionary objectForKey:#"tickets"];
for (NSDictionary *ticketDict in ticketsArray) {
Ticket *ticketToStore = [[Ticket alloc]init];
ticketToStore.ticketID = [ticketDict objectForKey:#"ticketID"];
ticketToStore.ticketTitle = [ticketDict objectForKey:#"ticketTitle"];
ticketToStore.numberOfAdults = [ticketDict objectForKey:#"numberOfAdults"];
ticketToStore.numberOfChildren = [ticketDict objectForKey:#"numberOfChildren"];
ticketToStore.redeemed = [ticketDict objectForKey:#"redeemed"];
ticketToStore.syncStatus = [NSNumber numberWithInt:1];
if ([DBConnect isExistingTicket:ticketToStore.ticketID]) {
[DBConnect updateTicketRedeemStatus:ticketToStore];
}else{
[DBConnect insertNewTicket:ticketToStore];
}
}
}else{
NSLog(#"======================Empty============================");
}
}
+ (NSString *)insertNewTicket:(Ticket *)ticket{
NSString *lastInsertedTicketId = #"";
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:dbName];
sqlite3 *database;
if(sqlite3_open([filePath UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement = "insert into tickets (ticket_id , ticket_title , adults , children , redeem_status , sync_status, redeemed_dateTime ) VALUES (?,?,?,?,?,?,?)";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
sqlite3_bind_text ( compiledStatement, 1, [ticket.ticketID UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text ( compiledStatement, 2, [ticket.ticketTitle UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int ( compiledStatement, 3, [ticket.numberOfAdults intValue] );
sqlite3_bind_int ( compiledStatement, 4, [ticket.numberOfChildren intValue]);
sqlite3_bind_text ( compiledStatement, 5, [ticket.redeemed UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int ( compiledStatement, 6, [ticket.syncStatus intValue] );
sqlite3_bind_int ( compiledStatement, 7, [ticket.redeemedDate timeIntervalSince1970]);
}
if(sqlite3_step(compiledStatement) != SQLITE_DONE ) {
NSLog( #"add new Ticket Error: %s", sqlite3_errmsg(database) );
}else{
lastInsertedTicketId = [NSString stringWithFormat:#"%lld",sqlite3_last_insert_rowid(database)];
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
return lastInsertedTicketId;
}
Use CoreData (wrapped into MagicalRecord) and undo. :)
How to parse this below "choices" on one array means when I have get "id" in array that all id values 108,109.... in 1st index in array but here is the 5 values in choices..so how to parse it
choices = (
{
id = 108;
label = Distributor;
},
{
id = 109;
label = "Clinical Lab";
},
{
id = 110;
label = Researcher;
},
{
id = 111;
label = "Current Customer";
},
{
id = 112;
label = "Past Customer";
}
);
Get in a single Step bro as
If your array is NSMutableArray then use as
NSArray *resultArray = [[NSArray arrayWithArray:temp] valueForKeyPath:#"id"]
If simple NSArray then use as
NSArray *resultArray = [jsonArray valueForKeyPath:#"id"]
You can do it using fast enumeration.
NSMutableArray *resultArray = [[NSMutableArray alloc] initWithCapacity:0];
// JSONDict is your JSON dict
for (NSDictionary *aDict in JSONDict[#"choices"]) {
[resultArray addObject:aDict[#"id"]];
}
NSLog(#"%#", resultArray);
Output:
(
108,
109,
110,
111,
112
)
If i understand your question properly, Then You can try this code for getting Ids in a Array:
NSMutableArray *arr = [[NSMutableArray alloc] init];
for (int i = 0;i<[choices count];i++)
{
[arr addObject:[[choices objectAtIndex:i] objectForKey:#"id"]];
}
NSLog(#"ID array : %#",arr);
[arr release];
try like this ,
NSMutableArray *idArray=[[NSMutableArray alloc]init];
for(int i=0;i<[jsonArray count];i++)
[idArray addObject:[[jsonArray objectAtIndex:i] valueForKey:#"id"]];
NSLog(#"%#",idArray);
here you'l get all the values in idArray.
I am having a requirement in which I have 5 keys stored in a NSDictionary corresponding to which I have stored 5 values from different arrays. My data structure looks like:
Dictionary is {
1 = (
{
SubRegionName = "abc";
WalkId = 123;
WalkName = xyz;
},
{
},....
2 = (
{
SubRegionName = "abc";
WalkId = 123;
WalkName = xyz;
},
{
},....
3 = (
{
SubRegionName = "abc;
WalkId = 123;
WalkName = xyz;
},
{
},....
4 = (
{
SubRegionName = "abc";
WalkId = 123;
WalkName = xyz;
},
{
},....
5 = (
{
SubRegionName = "abc";
WalkId = 123;
WalkName = xyz;
},
{
},
)
The above data I am getting from sqlite according to some Id say tempId(1,2,3,4,5) and I want to use them separately. As I have to display the walkName as cell.textlabel.text and SubregionName as cell.detailtext.text in tableview.
I am not getting how to access this data from the dictionary. Can anyone please suggest me right way to do it.
My code is:
// For Database queries (To get data from database) ***********
-(void)getMainRegions
{
sqlite3 *walkNameDB;
if (sqlite3_open([[self databasePath] UTF8String], &walkNameDB) != SQLITE_OK) {
sqlite3_close(walkNameDB);
NSAssert(0, #"Failed to open Walk name database");
}
NSString *regionQuery = #"SELECT Rid,RName from MainRegions";
sqlite3_stmt *teststatement = nil;
// NSLog(#"%d",sqlite3_prepare_v2(walkNameDB,[regionQuery UTF8String], -1, &teststatement, nil));
if (sqlite3_prepare_v2(walkNameDB,[regionQuery UTF8String], -1, &teststatement, nil) == SQLITE_OK)
{
RNameArray = [[NSMutableArray alloc] init];
RIdArray = [[NSMutableArray alloc] init];
while( sqlite3_step(teststatement) == SQLITE_ROW )
{
NSNumber *RId;
int temp1 = (int)sqlite3_column_int(teststatement, 0);
RId = [[NSNumber alloc] initWithInt:temp1];
char *RNameCharacter;
RNameCharacter = (char *) sqlite3_column_text(teststatement, 1);
NSString *RNameString = [[NSString alloc] initWithUTF8String:RNameCharacter];
[RNameArray addObject:RNameString];
[RIdArray addObject:RId];
}
}
[self getWalks];
}
-(void)getWalks
{
sqlite3 *walkNameDB;
if (sqlite3_open([[self databasePath] UTF8String], &walkNameDB) != SQLITE_OK) {
sqlite3_close(walkNameDB);
NSAssert(0, #"Failed to open Walk name database");
}
RegionWalksDictionary = [[NSMutableDictionary alloc] init];
for(regionId in RIdArray)
{
regionWalkArray = [[NSMutableArray alloc] init];
NSString *walkQuery = [[NSString alloc] initWithFormat:#"SELECT Wid,WName,SName from Walks,SubRegions WHERE Walks.Sid=SubRegions.Sid AND Rid = %d",[regionId integerValue] ];
sqlite3_stmt *walkstatement = nil;
// NSLog(#"%d",sqlite3_prepare_v2(walkNameDB,[walkQuery UTF8String], -1, &walkstatement, nil));
if (sqlite3_prepare_v2(walkNameDB,[walkQuery UTF8String], -1, &walkstatement, nil) == SQLITE_OK)
{
while( sqlite3_step(walkstatement) == SQLITE_ROW )
{
NSNumber *WId;
int temp1 = (int)sqlite3_column_int(walkstatement, 0);
WId = [[NSNumber alloc] initWithInt:temp1];
char *WNameCharacter;
WNameCharacter = (char *) sqlite3_column_text(walkstatement, 1);
NSString *WNameString = [[NSString alloc] initWithUTF8String:WNameCharacter];
char *SNameCharacter;
SNameCharacter = (char *) sqlite3_column_text(walkstatement, 2);
NSString *SNameString = [[NSString alloc] initWithUTF8String:SNameCharacter];
NSMutableDictionary *tempWalk = [[NSMutableDictionary alloc] init];
[tempWalk setObject:WId forKey:#"WalkId"];
[tempWalk setObject:WNameString forKey:#"WalkName"];
[tempWalk setObject:SNameString forKey:#"SubRegionName"];
[regionWalkArray addObject:tempWalk];
}
}
[RegionWalksDictionary setObject:regionWalkArray forKey:regionId];
// NSLog(#"arr%#",RegionWalksDictionary);
}
}
//*** Methods to get data from database ends here **************
Try this way...
for(id dict in RegionWalksDictionary){
NSLog(#"WalkId: %#",[[[RegionWalksDictionary objectForKey:dict]objectAtIndex:0]objectForKey:#"WalkId"] );
NSLog(#"WalkName: %#",[[[RegionWalksDictionary objectForKey:dict]objectAtIndex:0]objectForKey:#"WalkName"] );
NSLog(#"SubRegionName: %#",[[[RegionWalksDictionary objectForKey:dict]objectAtIndex:0]objectForKey:#"SubRegionName"] );
NSLog(#"----");
}
I have used as following (comment if this is not the structure or your data)
NSMutableDictionary *RegionWalksDictionary=[NSMutableDictionary new];
NSMutableArray *regionWalkArray=[NSMutableArray new];
NSMutableDictionary *tempWalk=[NSMutableDictionary new];
[tempWalk setObject:#"wk1" forKey:#"WalkId"];
[tempWalk setObject:#"wkName1" forKey:#"WalkName"];
[tempWalk setObject:#"srName1" forKey:#"SubRegionName"];
[regionWalkArray addObject:tempWalk];
[RegionWalksDictionary setObject:regionWalkArray forKey:#"1"];
[RegionWalksDictionary setObject:regionWalkArray forKey:#"2"];
[RegionWalksDictionary setObject:regionWalkArray forKey:#"3"];
NSLog(#"tempWalkd dict is %#",RegionWalksDictionary);
try this
NSString * walkName = [[parentDic objectForKey:[NSString stringWithFormat:#"%d",indexPath.row]] objectForKey:#"WalkName"];
NSString * SubregionName = [[parentDic objectForKey:[NSString stringWithFormat:#"%d",indexPath.row]] objectForKey:#"SubRegionName"];
It seems you have an NSDictionary with your 5 keys, and inside that you have an NSArray with a single element that is a NSDictionary. Although I might be wrong, try this:
NSDictionary *dictionaryForKey1 = [[myDictionary objectForKey:#"1"] objectAtIndex:0];
You can then use this:
NSString *walkName = [dictionaryForKey1 objectForKey:#"WalkName"];
AH! now I see it -- there are 5 arrays of length 1
NSArray *array1 = dict[#"1];
NSDictionary *details = array1[0];
//print each var
id WalkName = details[#"WalkName"];