sorting an NSArray of NSDates - cocoa

I have an NSArray of NSDate objects and I want to sort them so that today is at 0, yesterday at 1 etc.
Is it ascending or descending, and do i use a function, selector or what?

There are different sort methods for NSArray because there may be different ways you want to sort things. NSSortDescriptors are a general way that give you a lot of options as far as what keys to use in sorting, what selectors you want to use on those keys, and overall order to use, etc. Or you can use functions or comparator blocks instead if your case requires that or if that's more convenient for your particular case.
To answer your first question, if you want today to be first, followed by yesterday then, yes, that is of course descending order.
To sort some dates in descending order you can just do this: (assuming an NSArray full of NSDates called 'dateArray'):
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"self" ascending:NO];
NSArray *descriptors = [NSArray arrayWithObject: descriptor];
[descriptor release];
NSArray *reverseOrder = [dateArray sortedArrayUsingDescriptors:descriptors];
Or, if you are building for iOS 4+ or Snow Leopard+ you can do this:
NSArray *reverseOrderUsingComparator = [dateArray sortedArrayUsingComparator:
^(id obj1, id obj2) {
return [obj2 compare:obj1]; // note reversed comparison here
}];

Try this magic:
Sort array of dates in ascending order.
i.e. dates getting later and later, or to put it another way, dates going into the future.
NSArray ascendingDates = [dates sortedArrayUsingSelector:#selector(compare:)];
Sort array of dates in descending order. (what the question asked)
i.e. dates getting earlier and earlier, dates going into the past or to put it another way: today is at index 0, yesterday at index 1.
NSArray* descendingDates = [[[dates sortedArrayUsingSelector:#selector(compare:)] reverseObjectEnumerator] allObjects];

Related

Sorting NsMutable Array

I am getting floor names and storing in _floorNames (NSMutableArray) by using
_floorNames=[conferenceHall floorDetails:office];
NSLog(#"floor names=%#",_floorNames);
This will print floor names like this.
GROUND,
THIRD,
FIRST,
SECOND
Now i want to sort that floor names NsMutableArray as
GROUND,
FIRST,
SECOND,
THIRD
I have used
NSSortDescriptor *aa=[[NSSortDescriptor alloc]initWithKey:floor ascending:YES selector:#selector(localizedCaseInsensitiveCompare:)];
NSArray *descriptors = [NSArray arrayWithObjects:aa, nil];
a = [array sortedArrayUsingDescriptors:descriptors];
But it will crash my application.
Any suggestions ...
Try this,
NSArray *arrFloorNames=[[NSArray alloc]initWithObjects:#"GROUND",#"THIRD",#"FIRST",#"SECOND", nil];
arrFloorNames = [arrFloorNames sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
NSLog(#"%#",arrFloorNames);
What you want is you never get!!!
"GROUND, THIRD, FIRST, SECOND" to "GROUND, FIRST, SECOND ,THIRD" is what you want.
No algorithm can sort these strings based on their internal representation in numerals. This is something like, 0..1..2..3. You want to sort these integers written in English. Sorting can be done alphabetically so your result will be as First, Groung, Second, Third.
How to achieve?
You need to create an object of dictionary, with mapped value of Third to 3, second to 2, ground to 0. Then sort those numerical values. And then get Keys based on values(0,1,2etc).

CoreData predicate latest stored date

I need to get the latest date from coredata
i found a way
NSSortDescriptor * sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"date" ascending:NO];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[fetchRequest setFetchLimit:1];
so sort them by date and then pick the first
however can this not be done more optimal? this approach looks like a brute force
sort is nlogn, but simple search for the max is n
You can actually ask SQL for just that value, not the object with that value:
NSExpression *date = [NSExpression expressionForKeyPath:#"date"];
NSExpression *maxDate = [NSExpression expressionForFunction:#"max:"
arguments:[NSArray arrayWithObject:maxDate]];
NSExpressionDescription *d = [[[NSExpressionDescription alloc] init] autorelease];
[d setName:#"maxDate"];
[d setExpression:maxSalaryExpression];
[d setExpressionResultType:NSDateAttributeType];
[request setPropertiesToFetch:[NSArray arrayWithObject:d]];
NSError *error = nil;
NSArray *objects = [managedObjectContext executeFetchRequest:request error:&error];
if (objects == nil) {
// Handle the error.
} else {
if (0 < [objects count]) {
NSLog(#"Maximum date: %#", [[objects objectAtIndex:0] valueForKey:#"maxDate"]);
}
}
This is described in more detail under Fetching Managed Objects -> Fetching Specific Values in the CoreData documentation.
On line 2 maxDate expression refers to itself (maxDate).
I assume this must be the "date" variable from the first line.
I guess that's pretty much the best way. I'm not sure whether there is a more efficient way since it has to compare every date anyway to figure out which the oldest is.
Here are 2 other ways:
1) You could work with BOOLs as an attribute of the managed object. (like oldest = 1)
However, you'd have to find a new "oldest" managed object every time you delete one.
2) You could just save the oldest one until it changes. This might save a lot of work if you have to find the oldest managedObject often.
It depends on your application (how many times you insert/remove managed objects and how many times you need the oldest object).

objective-c custom sorting

So, having struggled with this for too long, without much documentation to go on, I thought I'd share my experience for those few who are even noobier than me.
There probably are much cleaner ways of achieving what I did, so please feel free to suggest improvements.
Here's what I wanted to do:
I have an NSArrayController which manages NSManagedObjects (say Thing). These objects have a name property which is of type NSString.
I wanted to sort the array of the array controller using the name of the managed objects. The common way to go about sorting a mutable array of strings should be something like:
[myMutableArrayOfStrings sortUsingSelector:#selector(caseInsensitiveCompare:)];
or:
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES selector:#selector(caseInsensitiveCompare:)];
NSArray *descriptorArray = [NSArray arrayWithObject:sortDescriptor];
[myArrayController setSortDescriptors:descriptorArray];
However, if the names happened to be numbers, caseInsensitiveCompare: would sort 11 before 8 (for instance).
Also, I wanted a name of a11b to be sorted AFTER a8b, meaning that I needed to chop the names of the managed objects into groups of digits and non-digit characters, then compare those individually.
What I came up with, was to make a category of NSString.
header file:
#import <Foundation/Foundation.h>
#interface NSString (MyString)
- (NSComparisonResult)myCustomCompare:(NSString *)anotherString;
#end
implementation file:
#import "MyString.h"
#implementation NSString (MyString)
- (NSComparisonResult)myCustomCompare:(NSString *)anotherString {
elaborate chopping up of strings into substrings..
For each of the 2 strings I made an NSMutableArray.
Then I determined if these substrings were NSNumbers, which have their own compare:, or NSStrings (caseInsensitiveCompare:)
Then I return an NSComparisonResult (NSOrderedAscending, NSOrderedSame or NSOrderedDescending)
}
#end
Then, in the implementation file of my Thing ManagedObject, I overrid the
- (NSComparisonResult)compare:(Thing *)anotherThing {
return [self.name myCustomCompare:anotherThing.name];
}
One also needs to import MyString.h in the Thing class.
Now, using
[[myArrayController arrangedObjects] sortUsingSelector:#selector(compare:)];
works like a charm.
Just one thing that's been bugging me. If a Thing's name property would contain decimal numbers, like for instance a1.4b and a1.39b, how would I be able to isolate these from the name? (a1.4b would incorrectly be sorted before a1.39b)
To make things even worse, a user could enter a Thing's name to be 1.3.55 ...

How to sort an NSArray on time interval instead of time of day?

Is there a way to sort on finish times for a race? I have an NSArray with a dictionary of NSStrings and one of the values is race finish time as an NSString. It sorts them all correctly as long as they have the same number of integers, like this: 54.13, 54.32, 54.52... but when one of them is longer, for example: 1:13.42 -- It puts it at the top of the list. How should I sort this so the slower times are at the bottom of the list. Here is what I currently have:
NSSortDescriptor * sortByTime2 = [[NSSortDescriptor alloc] initWithKey:#"raceTime" ascending:YES];
NSArray * descriptors2 = [NSArray arrayWithObject:sortByTime2];
myArray = [myArray sortedArrayUsingDescriptors:descriptors2];
thanks,
R
The strings "raceTime" are just mere string, they don't represent time. When you want to compare these, you need to convert these string to instances of NSData, then sort. You can use NSSortDescriptor and initialize it with a selector which will do the conversion and return the appropriate order.

Sorting NSMutableArray with NSStrings in alphabetical order

I have a NSMutableArray with NSStrings and I want to sort them in alphabetical order, seems it's no hard, but I didn't find nice solution. Help me please.
Using sortUsingSelector: method with compare: as comparing selector:
NSMutableArray* strings = [NSMutableArray arrayWithObjects:#"dog", #"ant", #"cat",nil];
[strings sortUsingSelector:#selector(compare:)];
NSLog(#"%#", strings);

Resources