sorting NSMutableArray contain NSArray using sortedArrayUsingComparator - iphone

I got problem for sorting array of nsdate.
so i have array of date inside nsmutablearray
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
NSArray *arrString = [[NSArray alloc] initWithObjects:#"2012-05-01", #"2012-02-01", #"2012-22-03", #"2012-05-01", #"2012-15-01", nil];
NSMutableArray *arrDate = [[NSMutableArray alloc] initWithCapacity:arrString.count];
for (NSString *item in arrString) {
NSDate *date = [dateFormatter dateFromString:item];
[arrDate addObject:date];
}
as i saw in many cases they use code like this to sort array:
NSArray *sortedArray = [arrDate sortedArrayUsingComparator:^(id firstObject, id secondObject) {
return [((NSDate *)firstObject) compare:((NSDate *)secondObject)];
}];
i tried to put my array on it, but not worked.
Anyone can help me how actully best way to sort nsmutablearray contain nsdate. I want to put the latest date at top of the index array.
So the real question is, how can i sort data inside arrDate?
Thank you.

Your date format does not match the date strings you are using.
yyyy-MM-dd hh:mm:ss
means the dates you supply should look something like:
2012-05-09 15:54:21
^^ Day
^^ Month
i.e. your strings are missing the hours, minutes and seconds and you have some dates with month 22 and month 15. If a date formatter can't parse a date, I think it returns nil which would mean you are trying to put nil into an array, which will cause an exception.
Edit
To actually sort the dates, your sample code looks OK except that you want most recent first, so reverse the compare:
NSArray *sortedArray = [arrDate sortedArrayUsingComparator:^(id firstObject, id secondObject) {
return [secondObject compare: firstObject];
}];
Or with a mutable array, you can sort in place:
[arrDate sortUsingComparator:^(id firstObject, id secondObject) {
return [secondObject compare: firstObject];
}];

Related

putting two lists of different objects and sort them by date, objective C

List 1 contains a list of object As and list 2 contains a list of object Bs.
Object A contains
date
quantity
message
Object B contains
date
email
first name
last name
Both object As and Bs has a property date in common. Are there anyway to merge them into one list and sorted by date.
You should merge them into one Array (NSArray's arrayByAddingObjectsFromArray:, right?)
and then you could use NSArray's sortedArrayUsingComparator:
NSArray *mergedArray = [array1 arrayByAddingObjectsFromArray:array2];
NSArray *orderedArray = [mergedArray sortedArrayUsingComparator: ^(id obj1, id obj2) {
NSDate *date1 = [obj1 date];
NSDate *date2 = [obj2 date];
return [date1 compare:date2];
}];
I haven't tested the code, but it's going to be something like that.
NSArray *listA = [NSArray arrayWithObjects:objA0, objA1, objA2, nil];
NSArray *listB = [NSArray arrayWithObjects:objB0, objB1, objB2, nil];
NSMutableArray *allObjects = [NSMutableArray arrayWithArray:listA];
[allObjects addObjectsFromArray:listB];
[allObjects sortUsingComparator:(NSComparator)^(id obj1, id obj2){
NSDate *date1 = obj1.date;
NSDate *date2 = obj2.date;
return [date1 compare:date2]; }];

Sort Array of Dictionaries by NSDate

I have an array of dictionaries. Within each dictionary, there is a a key dateOfInfo (an NSDate) and several other things. I want to sort the array by each dictionaries dateOfInfo with the most recent being the first result.
How can I do this?
You can sort using NSSortDescription, e.g.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey: #"dateOfInfo" ascending: NO];
NSArray *sortedArray = [array sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
You can also use the method
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context
The basic bubble sorting algorithm would work. In this case you need to loop through your array, use valueForKey message on [array objectAtIndex:] to get the NSDate values. For comparing dates see this post . So if you are sorting in ascending order of date, just add the object with the lower date (remember bubble sort comparisons?) to an array which will hold your sorted result.
try like this,
NSDateFormatter *fmtDate = [[NSDateFormatter alloc] init];
[fmtDate setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss"];
NSComparator compareDates = ^(id string1, id string2)
{
NSDate *date1 = [fmtDate dateFromString:string1];
NSDate *date2 = [fmtDate dateFromString:string2];
return [date1 compare:date2];
};
NSSortDescriptor * sortDesc1 = [[NSSortDescriptor alloc] initWithKey:#"StartTime" ascending:YES comparator:compareDates];
[youArray sortUsingDescriptors:#[sortDesc1]];

Sort by Date: NSArray with NSArray with Date-Object

I have a simple NSArray which has some arrays as objects which has some dates and strings as objects:
NSArray (main array) ---------------> table view
NSArray (secondary array)---> table view cell
NSDate --------------------> table view cell text label
NSString -------------------> table view cell detail text label
etc.
I use the main array for my table view -> each cell got it's own 'secondary array'.
Now I want to sort the main array by the NSDate object. It sounds very easy but I have found no solution on the web for it.
I thought about using NSSortDesriptors but those just sort the array by the objects in the main array and not in the secondary array.
Hopefully you can help me
EDIT: Would it fix the problem if I use a NSDictionary as the secondary array?
You should be able to use NSArray sortedArrayUsingComparator if your app is targeted for iOS 4.0 or later:
NSArray *sortedArray = [mainArray sortedArrayUsingComparator: ^(id obj1, id obj2) {
return [[obj1 objectAtIndex:0] compare:[obj2 objectAtIndex:0]];
}];
This assumes that the date field is always in index 0 of the internal array. It would probably be a bit cleaner if you used a dictionary and keyed the date field by name, but if you are comfortable with the date field always remaining in index 0 then the above should work.
Assuming I've understood your data structure correctly, this should be close:
NSArray *sortedArray = [mainArray sortedArrayUsingComparator:^(id ary1, id ary2) {
NSArray *array1 = (NSArray *)ary1;
NSArray *array2 = (NSArray *)ary2;
NSDate *date1 = (NSDate *)[array1 objectAtIndex:0];
NSDate *date2 = (NSDate *)[array2 objectAtIndex:0];
return [date1 compare:date2];
}];

iPhone PList and NSDate issues

I am doing:
NSString *path = [[self class] pathForDocumentWithName:#"Alarms.plist"];
NSArray *alarmDicts = [NSMutableArray arrayWithContentsOfFile:path];
if (alarmDicts == nil)
{
NSLog(#"MER. Unable to read plist file: %#", path);
path = [[NSBundle mainBundle] pathForResource:#"Alarms"
ofType:#"plist"];
alarmDicts = [NSMutableArray arrayWithContentsOfFile:path];
}
_displayedObjects = [[NSMutableArray alloc]
initWithCapacity:[alarmDicts count]];
for (NSDictionary *currDict in alarmDicts)
{
Alarm *alarm = [[Alarm alloc] initWithDictionary:currDict];
[_displayedObjects addObject:alarm];
}
pathForDocumentWithName just a helper method, assume it works (it does). I add all of the values of the plist to an object, and store it in an array. Now if I do something like this:
NSUInteger index = [indexPath row];
id alarm = [[self displayedObjects] objectAtIndex:index];
NSString *title = [alarm title];
[[cell detailTextLabel] setText:title];
It works perfectly fine. But when trying to format the NSDate type in the plist file (listed as 'datetime')
NSDate *datetime = [alarm datetime];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"hh:mm"];
[[cell textLabel] setText:[formatter stringFromDate:datetime]];
It throws the NSLog for alarmDicts being nil, and returns nil for the string. I'm out of ideas, and have been trying for a few hours to solve this. Anyone have any ideas?
Also, if I print out the description for datetime, it works perfectly. Only nils and errors out when I attempt to use the NSDateFormatter on it.
A massive guess, but are you sure the dates in your property list are being read in as NSDate objects? If I were you, I'd check the type of your apparent NSDate objects, e.g.
NSLog(#"%#", [[alarm datetime] class]);
I would be suspicious that they're being loaded as NSStrings, which NSDateFormatter will decline to process — but they'll still appear to log correctly.
Unrelated comment: I'm sure it's a copy and paste error only, but you're leaking 'Alarm' objects at the bottom of your first snippet of code.

Date Sectioned table?

I have a plist which contains an array of NSDictionary 's which represent a certain event each dictionary contains a few pieces of information about the event and a NSDate with the date of the event e.g.
I wish to create a sectioned table view with this date very much like in the Calendar app which ships with the iPhone when you click on the "List" view. You can see there are only sections for the dates where there are events.
So whats the best way to find out to begin with how many NSDictionary 's have the same date (so I know how many sections to create and how many rows in each section, as each section will have a different amount or rows).
Thanks
I did something very similar to this for Reconnected except my sections are for years (see the History screenshot).
Sort the array by the date key.
Start with the first item. The date of the first item represents the first segment. In my case, I only care about the year.
Create an array for the section with the date. Add the currently inspected to the section's array. Add the section's array to another array that will be the array of all sections in your table.
Move on to the next item. If the next item's date equals the previous item's date, add the current item to the current section's array. Otherwise, apply step #3 to the new date.
Repeat the previous step for rest of the array from your plist.
At the end of step 5, you should have an array of sections. From that section you can send it a message for the number of NSDictionary's you've added to the section which will represent each rows in your table.
After a bit of playing around this is what I have come up with, at the moment its just a foundation tool to keep it clear.
#import <Foundation/Foundation.h>
NSDate* normalizedDateWithDate(NSDate *date) {
NSCalendar *calendar = [NSCalendar currentCalendar];
unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *comp = [calendar components:unitFlags fromDate:date];
return [calendar dateFromComponents:comp];
}
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *plistPath = #"flights.plist";
NSArray *array = [[NSArray alloc] initWithContentsOfFile:plistPath];
NSMutableSet *flightDates = [[NSMutableSet alloc] init];
for (NSDictionary *oneFlight in array)
[flightDates addObject:normalizedDateWithDate([oneFlight objectForKey:#"flightDate"])];
NSLog(#"Number of Sections Required: %d", [flightDates count]);
NSMutableDictionary *datesAndFlights = [[NSMutableDictionary alloc] init];
for (NSDate *fDate in flightDates) {
NSMutableArray *sectionFlights = [[NSMutableArray alloc] init];
for (NSDictionary *oneFlight in array) {
if ([normalizedDateWithDate([oneFlight objectForKey:#"flightDate"]) isEqualToDate: normalizedDateWithDate(fDate)])
{
[sectionFlights addObject:oneFlight];
}
}
[datesAndFlights setObject:sectionFlights forKey:normalizedDateWithDate(fDate)];
[sectionFlights release];
}
NSEnumerator *enumerator = [datesAndFlights keyEnumerator];
NSDate *key;
while ((key = [enumerator nextObject])) {
NSLog(#"Key: %#", key);
for (NSDictionary *oneFlight in [datesAndFlights objectForKey:key]) {
NSLog(#"flightNumber: %# and Total Time: %#", [oneFlight objectForKey:#"flightNumber"], [oneFlight objectForKey:#"totalTime"]);
}
}
[array release];
[flightDates release];
[datesAndFlights release];
[pool drain];
return 0;
}
This is just what I have managed to put together and it seems to work but if anyone can see a way to make this better or more concise please say so! Also the function at the top which I use to make sure the date is always at time 00:00:00 when I compare it I have seen the NSCalendar – rangeOfUnit:startDate:interval:forDate: method in the documentation does anyone know if its better to use this instead?
Thanks