Order Date Strings in an Array - ios

I have generated an Array of strings, each is a date from a NSDictionary (parsed from a plist file), the issue is that when creating the Array the NSDictionary has the years in a random order.
my code:
NSString *path = [[NSBundle mainBundle] pathForResource:_country ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
tableData = [[NSMutableArray alloc] init];
for (id key in dict) {
for (NSString *date in [dict objectForKey:key]){
NSString *baseString = #"";
baseString = [baseString stringByAppendingFormat:#"%# %#", date, key];
[tableData addObject:baseString];
}
}
So the above outputs strings like: December 05 2014
What I need is to find a way to then order this array so that the oldest date is first.

The NSArray class has a -sortedArrayUsingComparator: method that you can use to sort it. See the reference here.
You need to provide a suitable comparator as a block, according to the date format you are using. Probably using NSScanner or NSDateFormatter...
NSArray *sortedArray = [tableData sortedArrayUsingComparator: ^(NSString *str1, NSString *str2) {
if (/* str1 goes before str2 */) {
return NSOrderedDescending;
}
else if (/* str1 goes after str2 */) {
return NSOrderedAscending;
}
else {
return NSOrderedSame;
}
}];

Related

Efficiently looping the jsonarray containing month and date that are of optional values

I have got the following json array. I want to concatenate statutory month (in terms of words )and add them into data base.
Sometimes months and date may not be present. Sometimes date will be present and months wont be present and vice versa. I have to handle this conditions and make store the date and month like 31 January,30April etc into the db.
[
{
"statutory_month": 1,
"statutory_date": 31
},
{
"statutory_month": 4,
"statutory_date": 30
},
{
"statutory_month": 7,
"statutory_date": 31
},
{
"statutory_month": 10,
"statutory_date": 31
}
]
Is there an efficient way to handle this situation without doing lots of loops?
Have you try this first create one months array. After that extract data from dictionary like this
NSArray *months = [[NSArray alloc] initWithObjects:#"Jan", #"Feb", #"Mar", #"Apr", #"May", #"Jun", #"July", #"Aug", #"Sept", #"Oct", #"Nov", #"Dec", nil];
NSArray *resultDate = [[NSArray alloc] init];
for (NSDictionary *dic in jsonArr) //jsonArr is your response arr
{
if([dic objectForKey:"statutory_month"] && [dic objectForKey:"statutory_date"]) {
NSString *dateObj = [NSString stringWithFormat:#"%d %#",[dic objectForKey:#"statutory_date"], [months objectAtIndex:[dic objectForKey:"statutory_month"]]];
}
else if([dic objectForKey:"statutory_date"]) {
NSString *dateObj = [NSString stringWithFormat:#"%d",[dic objectForKey:#"statutory_date"]];
}
else if([dic objectForKey:"statutory_month"]) {
NSString *dateObj = [NSString stringWithFormat:#"%#",[months objectAtIndex:[dic objectForKey:"statutory_month"]]];
}
else {
NSString *dateObj = #"No date";
}
[resultDate addObject:dateObj];
}
Hope this will help you.
You can take one array of Response:
NSArray *arr = //response;
for (NSDictionary *dic in arr)
{
if([dic objectForKey:"statutory_month"])
//add
if([dic objectForKey:"statutory_date"])
//add
}
P.S I didn't try it my self. But Hope it will Help you.

how to get nsDictionary element by using for-in

NSDictionary *myDict = #{#"one":#"1",#"two":#"2"};
for (NSDictionary* tmp in myDict) {
NSLog(#"%#",tmp);
}
resut:
my tmpis NSString
I want to get a dictionary with key= one , value = 1
for in for NSDictionary will iterate the keys.
for (NSString * key in myDict) {
NSLog(#"%#",key);
NSString * value = [myDict objectForKey:key];
}
If you want to get a dictionary. You have to create a dictionary from these values
for (NSString * key in myDict) {
NSLog(#"%#",key);
NSString * value = [myDict objectForKey:key];
NSDictionary * dict = #{key:value};
}
Or you should init like this:
NSArray *arrDict = #[{#{"one":#"1"},#{#"two":#"2"}];
for (NSDictionary* tmp in arrDict) {
NSLog(#"%#",tmp);
}
You can get all keys from your dic then add the key and value to your new dic like this:
NSDictionary *myDict = #{#"one":#"1",#"two":#"2"};
NSArray *keys = [myDict allKeys];
for (NSString *key in keys) {
NSDictionary *yourDic = #{key: [myDict valueForKey:key]};
NSLog(#"%#", yourDic);
}
You didn't create it that way. If you wanted to have a NSDictionary inside another NSDictionary you should write something like this :
NSDictionary *myDict = #{
#"firstDict" : #{
#"one":#"1"
},
#"secondDict": #{
#"two":#"2"
}
};
Above code will create a NSDictionary with two dictionaries at keys #firstDict and #secondDict.
Also, bear in mind, that because dictionaries are key-value pairs, using a for-in loop, actually loops through the keys in that dictionary. So your code is equivalent to:
for(NSString *key in dict.allKeys) { ... }
I got the solution
NSDictionary *myDict = #{#"one":#"1",#"two":#"2"};
NSMutableArray *arrayObject = [[NSMutableArray alloc]init];
NSMutableArray *arrayKey = [[NSMutableArray alloc]init];
NSMutableArray *arrayObjectKey = [[NSMutableArray alloc]init];
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
for (NSString *stringValue in myDict.allValues)
{
[arrayObject addObject:stringValue];
}
for (NSString *stringKey in myDict.allKeys)
{
[arrayKey addObject:stringKey];
}
for(int i = 0;i<[arrayKey count];i++)
{
dict = [[NSMutableDictionary alloc]initWithObjectsAndKeys:[NSString stringWithFormat:#"%#",[arrayKey objectAtIndex:i]],#"key",nil];
[dict setObject:[NSString stringWithFormat:#"%#",[arrayObject objectAtIndex:i]] forKey:#"value"];
[arrayObjectKey addObject:dict];
}
NSLog(#"The arrayObjectKey is - %#",arrayObjectKey);
The Output is
The arrayObjectKey is -
(
{
key = one;
value = 1;
},
{
key = two;
value = 2;
}
)
Create the dictionary:
NSDictionary *myDict = [NSDictionary dictionaryWithObjectsAndKeys:#"1",#"One",#"2","Two",nil];
Get a value out using:(this example tmp will be 1)
NSString *tmp = [myDict objectForKey:#"One"];
Display the output in console:
NSLog(#"%#",tmp);
To display the whole NSDictionary
NSLog (#"contents of myDict: %#",myDict);
What you are doing is creating a dictionary with key-value pairs. I think what you want to do is have an array with dictionaries.
NSArray *myArray = #[#{#"one":#"1"}, #{#"two":#"2"}];
for (NSDictionary* tmp in myArray) {
NSLog(#"%#",tmp);
}
However I don't see a point in doing this. What you could do is:
NSDictionary *myDict = #{#"one":#"1",#"two":#"2"};
for (NSString* key in [myDict allKeys]) {
NSLog(#"%# = %#", key, myDict[key]);
}

How to detect if a dictionary is empty or null

I am receiving a JSON string that I need to iterate to retrieve some objects values.
This is the structure
-meta
-objects
|_cabdriver
|_employee
|client
There are objects under the objects tree and there are also child nodes, like cabdriver and client. The child node cabdriver has also another child node called employee.
This is the way I am iterating it:
NSArray *messageArray = [json objectForKey:#"objects"];
historialServicios = [[NSMutableArray alloc]init];
// Parse and loop through the JSON
for (dictionary in messageArray) {
//datos de nivel objects
NSString * date = [dictionary objectForKey:#"date"];
NSString * origin = [dictionary objectForKey:#"origin"];
NSString * destiny = [dictionary objectForKey:#"destiny"];
NSString * rate = [dictionary objectForKey:#"service_rate"];
NSString * state = [dictionary objectForKey:#"state"];
NSString * time_service = [dictionary objectForKey:#"time_service"];
NSString * id_service = [dictionary objectForKey:#"id"];
//datos de nivel cliente
NSDictionary *level2Dict = [dictionary objectForKey:#"client"];
NSString *client_id = [level2Dict objectForKey:#"id"];
//datos de nivel cabdriver
NSDictionary *cabdriverLevelDict=[dictionary objectForKey:#"cabdriver"];
//datos de nivel employee
NSDictionary *employeeLevelDict = [cabdriverLevelDict objectForKey:#"employee"];
//datos del employee
NSString *driverName = [employeeLevelDict objectForKey:#"name"];
NSString *driverLastname = [employeeLevelDict objectForKey:#"lastname"];
NSString *driverPhone = [employeeLevelDict objectForKey:#"phone"];
NSString *driverId = [employeeLevelDict objectForKey:#"id"];
[historialServicios addObject:#{
#"time_service": time_service,
#"id_service": id_service,
#"rate": rate,
#"destiny": destiny,
#"state": state,
#"origin": origin,
#"client_id":client_id,
#"date": date,
#"driverName":driverName,
#"driverLastname": driverLastname,
#"driverPhone": driverPhone,
#"driverId": driverId
}];
NSLog(#"DESPUES DE ANADIR OBJETOS");
NSLog(#"OBJETO ANADIDO==>TIME SERVICE = %#, ID SERVICE=%#, SERVICE RATE=%#,SERVICE DATE=%#,DESTINY=%#, STATE =%#,CLIENT ID=%#, ORIGIN=%#,DRIVER NAME=%#, DRIVER LASTNAME=%#,DRIVER PHONE=%#, DRIVER ID=%#",time_service,id_service,rate,date,destiny,state,client_id,origin,driverName,driverLastname,driverPhone,driverId);
//insertamos objetos en diccionario historialServicios
}
Everything works fine if the object has all nodes but some times, the node cabdriver is empty and doesn't have the employee child node. If it is the case I get an exception is thrown and the app crashes.
How can I determined if the node employee doesn't exist and avoid to get the exception?
Thank you.
You could declare a category to deal with the [NSNull null] values that are injected into your json.
#interface NSDictionary (NilNull)
- (id)optionalObjectForKey:(id)key;
- (id)optionalObjectForKey:(id)key defaultValue:(id)defaultValue;
#end
#implementation NSDictionary (NilNull)
- (id)optionalObjectForKey:(id)key {
return [self optionalObjectForKey:key defaultValue:nil];
]
- (id)optionalObjectForKey:(id)key defaultValue:(id)defaultValue {
id obj = [self objectForKey:key];
return (obj == [NSNull null] || !obj) ? defaultValue : obj;
}
#end
Then use that instead:
NSDictionary *cabdriverLevelDict = [dictionary optionalObjectForKey:#"cabdriver"];
NSDictionary *employeeLevelDict = [cabdriverLevelDict optionalObjectForKey:#"employee"];
You haven't posted the contents of your exception, but from the looks of it, it's probably related to trying to add nil values to your new dictionary.
Then use a default value of [NSNull null] for all your data lookups that produce objects with which you will construct your final dictionary. The full lookup source will now be like this:
NSString * date = [dictionary optionalObjectForKey:#"date" defaultValue:[NSNull null]];
NSString * origin = [dictionary optionalObjectForKey:#"origin" defaultValue:[NSNull null]];
NSString * destiny = [dictionary optionalObjectForKey:#"destiny" defaultValue:[NSNull null]];
NSString * rate = [dictionary optionalObjectForKey:#"service_rate" defaultValue:[NSNull null]];
NSString * state = [dictionary optionalObjectForKey:#"state" defaultValue:[NSNull null]];
NSString * time_service = [dictionary optionalObjectForKey:#"time_service" defaultValue:[NSNull null]];
NSString * id_service = [dictionary optionalObjectForKey:#"id" defaultValue:[NSNull null]];
//datos de nivel cliente
NSDictionary *level2Dict = [dictionary optionalObjectForKey:#"client" defaultValue:[NSDictionary dictionary]];
NSString *client_id = [level2Dict optionalObjectForKey:#"id" defaultValue:[NSNull null]];
//datos de nivel cabdriver
NSDictionary *cabdriverLevelDict=[dictionary optionalObjectForKey:#"cabdriver" defaultValue:[NSDictionary dictionary]];
//datos de nivel employee
NSDictionary *employeeLevelDict = [cabdriverLevelDict optionalObjectForKey:#"employee" defaultValue:[NSDictionary dictionary]];
//datos del employee
NSString *driverName = [employeeLevelDict optionalObjectForKey:#"name" defaultValue:[NSNull null]];
NSString *driverLastname = [employeeLevelDict optionalObjectForKey:#"lastname" defaultValue:[NSNull null]];
NSString *driverPhone = [employeeLevelDict optionalObjectForKey:#"phone" defaultValue:[NSNull null]];
NSString *driverId = [employeeLevelDict optionalObjectForKey:#"id" defaultValue:[NSNull null]];
Try this here:
if( cabdriverLevelDict.allkeys.count ){
// Do something with the dict
} else {
// dict is empty
}
Basically, you need to check every single result that you get. If you don't do that, your app is open to attacks, and one attack might allow a hacker into the user's device and cause unlimited damage. Where you expect a dictionary, you might get nil, you might get a null, you might get a number, or a string, just anything. It's quite simple.
NSDictionary* dict = ...;
if (! [dict isKindOfClass:[NSDictionary class]]) dict = nil;
In Objective-C, nil objects are quite safe. You can use objectForKey [#"employee"], for example, and all that will happen is that you get nil as the result. And you could have received nil anyway.
There is no point checking for [NSNull null] only, because any other result that the server gave you will crash your app just the same. Just check for what you actually expect. Throwing away incorrect data is fine, after all the JSON deserialiser will throw away everything if just a single byte of data is wrong.
Sometimes you need to do a bit more care because servers misbehave and you have to cope with it. For example, a server supposed to return an array of dictionaries might give you just a dictionary if there is only one, so you would check for example
NSArray* arrayOfDicts = ...;
if ([arrayOfDicts isKindOfClass:[NSDictionary class]] arrayOfDicts = #[arrayOfDicts];
else if (! [arrayOfDicts isKindOfClass:[NSArray class]] arrayOfDicts = nil;
As others have pointed out, if any of the objects passed into the dictionary are nil, that will throw an exception that crashes your app. By doing the following:
[historialServicios addObject:#{
#"time_service": time_service,
#"id_service": id_service,
#"rate": rate,
#"destiny": destiny,
#"state": state,
#"origin": origin,
#"client_id":client_id,
#"date": date,
#"driverName":driverName,
#"driverLastname": driverLastname,
#"driverPhone": driverPhone,
#"driverId": driverId
}];
You're depending that all these objects (eg time_service, id_service, etc) are not nil. As you've pointed out, they can be nil, so you need to have a means of checking for each object you do. I would recommend using an NSMutableDictionary, making a category method that only adds the key/value pair if they are both not nil:
#implementation NSMutableDictionary (Util)
-(void)setObjectOrRemoveIfNil:(id)anObject forKey:(id<NSCopying>)aKey
{
if (anObject == nil)
{
[self removeObjectForKey:aKey];
}
else
{
[self setObject:anObject forKey:aKey];
}
}
#end
And then put together your dictionary like so:
NSMutableDictionary* values = [NSMutableDictionary dictionary];
[values setObjectOrRemoveIfNil:time_service forKey:#"time_service"];
[values setObjectOrRemoveIfNil:id_service forKey:#"id_service"];
//Keep going with the rest of your values.
Finally we use that dictionary like you did already:
[historialServicios addObject:values];
check the count for the dictionary
if ([cabdriverLevelDict count] == 0) {
NSLog("empty");
}
else{
// Do your stuff !!
}
if (![cabdriverLevelDict isKindOfClass:[NSNull class]] ){
//do something
}
try this
You can try
NSDictionary *employeeLevelDict = [cabdriverLevelDict objectForKey:#"employee"];
if (employeeLevelDict.count != 0)
{
// do something if dict is not empty
}
else
{
}];

Put multiple arrays in Dictionary

I am parsing a CSV file multiple times with for loop, here I need to store these arrays one by one dictionary. There are very less questions in stack about adding NSArray to NSDictionary. I am parsing CSV with below code but I strucked at storing in NSDictionary, The program is terminating and showing warning at assigning string to dictionary
for (i=0; i<=57; i++) {
NSString *keysString = [csvArray objectAtIndex:i];
NSArray *keysArray = [keysString componentsSeparatedByString:#","];
NSLog(#"Serail No %d %#",i,keysArray);
NSString *string = [NSString stringWithFormat:#"%d", i];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjects: keysArray forKeys: string];
}
NSMutableDictionary *dict = [[NSMutableDictionary alloc]init];
for (i=0; i<=57; i++) {
NSString *keysString = [csvArray objectAtIndex:i];
NSArray *keysArray = [keysString componentsSeparatedByString:#","];
NSString *key = [NSString stringWithFormat:#"serial%d",i];
[dict setObject:keysArray forKey:key];
}
To get back data from dictionary,
NSArray *array = [dict valueForKey:#"serial24"];//to get array 24.
If I understand you correctly, you want to add the arrays to a dictionary, with the key being the string value of integer i ? What you need to do is allocate the dictionary outside your loop -
NSMutableDictionary *dict=[NSMutableDictionary new];
for (i=0; i<=57; i++) {
NSString *keysString = [csvArray objectAtIndex:i];
NSArray *keysArray = [keysString componentsSeparatedByString:#","];
NSLog(#"Serial No %d %#",i,keysArray);
NSString *string = [NSString stringWithFormat:#"%d", i];
dict[string]=keysArray;
}
I am not sure why you would want to do this, because this is basically an array. You could simply do -
NSMutableArray *outputArray=[NSMutableArray new];
for (NSString *keysString in csvArray) {
NSArray *keysArray = [keysString componentsSeparatedByString:#","];
[outputArray addObject:keysArray];
}

convert array format according to array character

I have array in this format
rows = [[NSArray alloc] initWithObjects:#"adam", #"alfred", #"ain", #"abdul", #"anastazja", #"angelica",
#"dennis" , #"deamon", #"destiny", #"dragon", #"dry", #"debug" #"drums",
#"Fredric", #"France", #"friends", #"family", #"fatish", #"funeral",
#"Mark", #"Madeline",
#"Nemesis", #"nemo", #"name",
#"Obama", #"Oprah", #"Omen", #"OMG OMG OMG", #"O-Zone", #"Ontario",
#"Zeus", #"Zebra", #"zed", nil];
But i need this in to following format
rows = #[#[#"adam", #"alfred", #"ain", #"abdul", #"anastazja", #"angelica"],
#[#"dennis" , #"deamon", #"destiny", #"dragon", #"dry", #"debug", #"drums"],
#[#"Fredric", #"France", #"friends", #"family", #"fatish", #"funeral"],
#[#"Mark", #"Madeline"],
#[#"Nemesis", #"nemo", #"name"],
#[#"Obama", #"Oprah", #"Omen", #"OMG OMG OMG", #"O-Zone", #"Ontario"],
#[#"Zeus", #"Zebra", #"zed"]];
Means that same starting character in to different dictionary
The easiest approach.
NSArray *rows = ...;
NSMutableDictionary *map = [NSMutableDictionary dictionary];
for (NSString *value in rows) {
NSString *firstLetter = [value substringToIndex:1];
if (!map[firstLetter]) {
map[firstLetter] = #[];
}
NSMutableArray *values = [map[firstLetter] mutableCopy];
[values addObject:value];
map[firstLetter] = values;
}
NSArray *finalRows = [map allValues];
Note that finalRows is not sorted.
If you want to sort your array by it's first letter, you can try this :
NSMutableArray *outputArray = [NSMutableArray new];
NSString *lastFirstLetter = nil;
for(NSString *value in rows) {
NSString *firstLetter = [[value substringToIndex:1] lowerString];
if(![lastFirstLetter isEqualToString:firstLetter]) {
lastFirstLetter = firstLetter;
[outputArray addObject:[NSMutableArray new]];
}
[[outputArray lastObject] addObject:value];
}
The idea is to iterate your input array and if the first letter of your word is different than the precedent, create a new array.

Resources