Sorting NSArray by file creation time - ios

I've read all answers about the subject, but still have my array unsorted. Please, help me with this issue. What's wrong with the code? Thanks in advance.
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filename error:NULL];
NSDate *date = [attributes fileCreationDate];
NSMutableArray *datesList = [[NSMutableArray alloc] init];
[datesList addObject:date];
NSArray *sortedArray = [[NSArray alloc] init];
sortedArray = [datesList sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2){
if ([obj1 date] > [obj2 date])
{
return (NSComparisonResult)NSOrderedAscending;
}
if ([obj1 date] < [obj2 date])
{
return (NSComparisonResult)NSOrderedDescending;
}
return (NSComparisonResult)NSOrderedSame;
}];
NSLog(#"sortedarray:%#",sortedArray);

First of all, you add to the array only one object :)
Your code should look like:
sortedArray = [datesList sortedArrayUsingComparator:^NSComparisonResult(NSDate *first, NSDate *second){
return [first compare:second];
}];
[NSDate compare:] returns `NSComparisonResult which is fine. You can add ! if you want to have opposite sorting direction.

Related

Sorting NSArray of Dictionary containing Date as String

I want to sort the following array based on the Date parameter but the problem is from a server I am not getting a timestamp, I am getting the date as a string, can anyone please help.
NSArray *array = #[
#{#"valid":#"Y",#"mof":#"ON",#"dof":#"17-05-2019",#"rtntype":#"CODE1",#"ret_prd":#"042019"},
#{#"valid":#"Y",#"mof":#"ON",#"dof":#"19-04-2019",#"rtntype":#"CODE1",#"ret_prd":#"032019"},
#{#"valid":#"Y",#"mof":#"ON",#"dof":#"19-04-2019",#"rtntype":#"CODE2",#"ret_prd":#"032019"}
];
I have tried applying the solution but it won't work as the Date we have is in NSString and not in NSDate or NSTimeInterval
[array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
if ([obj1 intValue] == [obj2 doubleValue])
return NSOrderedSame;
else if ([obj1 intValue] < [obj2 doubleValue])
return NSOrderedAscending;
else
return NSOrderedDescending;
}];
I am assuming you have a specific reason to keep data as it is instead of parsing into model class keep it handy.
In your scenario you could try the following code to sort the array:
NSArray *array = #[
#{#"valid":#"Y",#"mof":#"ON",#"dof":#"19-04-2019",#"rtntype":#"CODE1",#"ret_prd":#"032019"},
#{#"valid":#"Y",#"mof":#"ON",#"dof":#"17-05-2019",#"rtntype":#"CODE1",#"ret_prd":#"042019"},
#{#"valid":#"Y",#"mof":#"ON",#"dof":#"19-04-2019",#"rtntype":#"CODE2",#"ret_prd":#"032019"}
];
//NSDateFormatter to convert NSString to NSDate
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd-MM-yyyy"];
NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
if ([obj1 isKindOfClass:[NSDictionary class]]
&& [obj2 isKindOfClass:[NSDictionary class]]) {
NSDictionary *dict1 = (NSDictionary *)obj1;
NSDictionary *dict2 = (NSDictionary *)obj2;
if ([dict1[#"dof"] isKindOfClass:[NSString class]]
&& [dict2[#"dof"] isKindOfClass:[NSString class]]) {
NSString *dof1 = (NSString *) dict1[#"dof"];
NSString *dof2 = (NSString *) dict2[#"dof"];
NSDate *date1 = [formatter dateFromString:dof1];
NSDate *date2 = [formatter dateFromString:dof2];
return [date1 compare:date2];//Update the return based on in which order you want the resulting array
}
}
return NSOrderedSame;
}];
NSLog(#"%#", sortedArray);
And the result is:
(
{
dof = "19-04-2019";
mof = ON;
"ret_prd" = 032019;
rtntype = CODE1;
valid = Y;
},
{
dof = "19-04-2019";
mof = ON;
"ret_prd" = 032019;
rtntype = CODE2;
valid = Y;
},
{
dof = "17-05-2019";
mof = ON;
"ret_prd" = 042019;
rtntype = CODE1;
valid = Y;
}
)

EXC_BREAKPOINT when using sortedArrayUsingComparator with a lot of objects

I'm trying to sort a set and it works fine most of the time. But when I start using my app on an old iPhone 5c and a lot of objects get into the set, I would eventually hit this error:
EXC_BREAKPOINT (code=EXC_ARM_BREAKPOINT, subcode=0xdefe)
here is the code plus stacktrace:
if(manager.allBeacons){
NSSet *beacons = [manager.allBeacons copy];
NSSet *filteredSet = [[NSSet alloc] initWithSet:[beacons filteredSetUsingPredicate:predicate]];
if(filteredSet){
//NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"RSSI" ascending:NO];
//NSArray *sortDescriptors = [NSArray arrayWithObject:descriptor];
//NSArray *sortedArray = [[NSArray alloc] initWithArray:[filteredSet.allObjects sortedArrayUsingDescriptors:sortDescriptors]];
NSArray *sortedArray = [filteredSet.allObjects sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
if([obj1 isKindOfClass:[BLUSBeacon class]] && [obj2 isKindOfClass:[BLUSBeacon class]]){
BLUSBeacon *beacon1 = obj1;
BLUSBeacon *beacon2 = obj2;
if(beacon1.RSSI.integerValue > beacon2.RSSI.integerValue){
return (NSComparisonResult)NSOrderedAscending;
}
if(beacon1.RSSI.integerValue < beacon2.RSSI.integerValue){
return (NSComparisonResult)NSOrderedDescending;
}
}
return (NSComparisonResult)NSOrderedSame;
}];
if(sortedArray){
self.beacons = sortedArray;
[self.tableView reloadData];
}
}
}
And here is the last step in the stacktrace in case it serves any purpose:
As you can see, I was trying to sort with descriptors initially, but that made it crash even sooner.
Any thoughts?

Trouble sorting custom objects in an NSArray numerically

If I'm trying to sort BL_Player by their playerScore property:
NSArray *sortedPlayers = [players sortedArrayUsingComparator: ^(BL_Player *a1, BL_Player *a2) {
return [a1.playerScore compare:a2.playerScore options:NSNumericSearch];
OR
NSArray *sortedPlayers = [players sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSInteger first = [(BL_Player *)a playerScore];
NSInteger second = [(BL_Player *)b playerScore];
return [first compare:second options:NSNumericSearch];
}];
both of which return bad receiver types. What's wrong with doing comparisons on ints or NSInteger?
Try this one:
NSArray *sortedPlayers = [players sortedArrayUsingComparator: ^(BL_Player *a1, BL_Player *a2) {
if (a1.playerScore > a2.playerScore) {
return NSOrderedAscending;
}
else if (a1.playerScore < a2.playerScore) {
return NSOrderedDescending;
}
else
return NSOrderedSame;
}
Change as per your requirement.
May help you.
A better approach to do this:
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"playerScore"
ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [players sortedArrayUsingDescriptors:sortDescriptors];
for descending order change YES to NO.

Sort values of NSMutableDictionary alphabetically

I have NSMutableDictionary with Integers as Key and NSString as Values for example:
Key -- Value
1 -- B
2 -- C
3 -- A
Now i want to Sort NSMutableDictionary alphabetically using values. So i want my dictionary to be like : Key(3,1,2)->Value(A,B,C). How can i perform this?
From Apple docs:
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Collections/Articles/Dictionaries.html#//apple_ref/doc/uid/20000134-SW4
Sorting dictionary keys by value:
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:63], #"Mathematics",
[NSNumber numberWithInt:72], #"English",
[NSNumber numberWithInt:55], #"History",
[NSNumber numberWithInt:49], #"Geography",
nil];
NSArray *sortedKeysArray =
[dict keysSortedByValueUsingSelector:#selector(compare:)];
// sortedKeysArray contains: Geography, History, Mathematics, English
Blocks ease custom sorting of dictionaries:
NSArray *blockSortedKeys = [dict keysSortedByValueUsingComparator: ^(id obj1, id obj2) {
if ([obj1 integerValue] > [obj2 integerValue]) {
return (NSComparisonResult)NSOrderedDescending;
}
if ([obj1 integerValue] < [obj2 integerValue]) {
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}];
try this logic
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:#"B",#"B",#"A",#"A",#"C",#"C", nil];
NSMutableArray *sortedArray = [NSMutableArray arrayWithArray:[dict allKeys]];
[sortedArray sortUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
for (NSString *key in sortedArray) {
NSLog(#"%#",[dict objectForKey:key]);
}

UITableView scroll to section that is closest to todays date

I have a tableview with a calendar it's appointments in it. Each day is a separate section.
You can see what I mean over here
Now I want that the tableview scrolls to the section of today or if there is no section for today to the closest one.
I know that I should use the following piece of code:
[tableView scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
Now I have an NSMutableDictionary that contains my sorted Appointments/day. You can see the function below:
-(NSDictionary *)sortKalendar:(NSMutableArray *)appointments{
NSMutableDictionary *buffer = [[NSMutableDictionary alloc] init];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd-MM-yyyy"];
for (int i = 0; i < appointments.count; i++) {
Appointment *object = [appointments objectAtIndex:i];
NSString *date = [formatter stringFromDate:object.app_start];
if(!(date == NULL) ){
NSLog(#"date is %#",date);
if ([buffer objectForKey:date]) {
[(NSMutableArray *)[buffer objectForKey:date] addObject:object];
} else {
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithObjects:object, nil];
[buffer setObject:mutableArray forKey:date];
}
}
}
NSDictionary *result = [NSDictionary dictionaryWithDictionary:buffer];
return result;
}
My question is now, how can I find the correct NSIndexpath ?
Thanks in advance !
EDIT
At the moment I'm using the following. But something is still not right.
NSArray *keys = [dictAppointments allKeys];
NSLog(#"KEYS ARE %#",keys) ;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd-MM-yyyy"];
NSArray *sortedArray = [keys sortedArrayUsingComparator:^(id obj1, id obj2) {
NSDate *date1 = [formatter dateFromString:obj1];
NSDate *date2 = [formatter dateFromString:obj2];
NSNumber *interval1 = [NSNumber numberWithDouble:[date1 timeIntervalSinceNow]];
NSNumber *interval2 = [NSNumber numberWithDouble:[date2 timeIntervalSinceNow]];
return (NSComparisonResult)[interval1 compare:interval2];
}];
NSLog(#"Sorted Array %#",sortedArray);
NSString *closestDateString = [sortedArray objectAtIndex:0];
NSLog(#"Closest date string is %#",closestDateString);
int section = [keys indexOfObject:closestDateString];
NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:0 inSection:section];
[tableView scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
This gives me the following logs:
2014-01-07 13:28:42.420 Adsolut[9579:60b] KEYS ARE (
"03-12-2013",
"20-12-2013",
"17-12-2013",
"05-01-2014",
"21-12-2013",
"31-12-2013",
"04-01-2014",
"06-01-2014",
"16-01-2014",
"29-12-2013",
"03-01-2014",
"11-01-2014",
"18-12-2013",
"31-01-2014"
)
2014-01-07 13:28:42.437 Adsolut[9579:60b] Sorted Array (
"03-12-2013",
"17-12-2013",
"18-12-2013",
"20-12-2013",
"21-12-2013",
"29-12-2013",
"31-12-2013",
"03-01-2014",
"04-01-2014",
"05-01-2014",
"06-01-2014",
"11-01-2014",
"16-01-2014",
"31-01-2014"
)
You can sort the array using time interval between appointment date and current date,
NSArray *keys = [yourDictionary allKeys];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd-MM-yyyy"];
NSArray *sortedArray = [keys sortedArrayUsingComparator:^(id obj1, id obj2) {
NSDate *date1 = [formatter dateFromString:obj1];
NSDate *date2 = [formatter dateFromString:obj2];
NSNumber *interval1 = [NSNumber numberWithDouble:abs([date1 timeIntervalSinceNow])];
NSNumber *interval2 = [NSNumber numberWithDouble:abs([date2 timeIntervalSinceNow])];
return (NSComparisonResult)[interval1 compare:interval2];
}];
And the closest date by,
NSString *closestDateString = [sortedArray objectAtIndex:0];
And from that,
int section = [keys indexOfObject:closestDateString];
NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:0 inSection:section];
Get the list of dates (from your dictionary or one you already have). Sort it. Loop over it (indexOfObjectPassingTest:) to find the date >= today (or use a predicate to filter and then take the first item from the result and get the index).
You have a sorted date array, don't you? Let's say it as dateArray.
Get today date object: NSDate * today = [NSDate date];
Search for dateArray to the nearest date, get the index of nearest date.
NSDate * today = [NSDate date] ;
__block NSUInteger section = NSNotFound ;
__block NSTimeInterval timeInterval = NSTimeIntervalSince1970 ;
[dateArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSDate * date = obj ;
NSTimeInterval ti = [today timeIntervalSinceDate:date] ;
if (ti < 0)
ti = -ti ;
if (ti <= timeInterval) {
section = idx ;
timeInterval = ti ;
} else {
*stop = YES ;
}
}] ;
You know the section index now, let's say it as sectionIndex, the first row index in the section is 0.
So the NSIndexPath is [NSIndexPath indexPathForRow:0 inSection:sectionIndex]

Resources