Sort NSMutableArray of objects by date - objective-c

self.objectSet = [NSMutableArray array];
//add objects to set
[self.objectSet sortUsingComparator:^NSComparisonResult(id a, id b) {
NSDate *firstDate = [(Entity *)a createdAt];
NSDate *secondDate = [(Entity *)b createdAt];
return [secondDate compare:firstDate];
}];
I want to sort the nsmutablearray by createdAt date. However the above code has no effect on the displayed table view. The data is unsorted.
Any ideas whats wrong?

Did you try to sort with sort descriptors?
Is it the same effect?
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"createdAt" ascending:YES];
[self.objectSet sortUsingDescriptors:#[sortDescriptor]];

Related

Ordering an NSArray with NSDictionaries with objects

I have an array of dictionaries that contains objects like in the image below:
The problem I have is that I need to order the array by dates, for example in the first object I have a dueDate that is greater than the dueDate of the second object, then I have to swap them, so in other word I need to order the dictionaries inside the array based on the dueDate in ascending order, anyone have ideas?, I have tried with NSpredicate, with sortDescriptors but it isnt working, here is my sortDescriptors code:
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"dueDate" ascending:YES];
NSSortDescriptor *descriptor2 = [[NSSortDescriptor alloc] initWithKey:#"overDueDate" ascending:YES];
NSArray *descriptors = #[descriptor, descriptor2];
tasksResultArray = [tasksResultArray sortedArrayUsingDescriptors:descriptors];
Thanks in advance.
It can be done easier:
arrayOfDictionaries = [arrayOfDictionaries sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
// The logic for comparing dates, and returning the corresponding result
NSDate *date1 = (NSDate *) [(NSDictionary *)obj1 objectForKey:#"dueDate"];
NSDate *date2 = (NSDate *) [(NSDictionary *)obj2 objectForKey:#"dueDate"];
return [date1 compare:date2];
}];

Sorting NSMutableArray by date

I want to sort a mutable array by date. My array contains several dict with keys say:key1,key2,birthday.Now, I have to sort by its birthday key:
I know that this can be done using:
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"birthday" ascending:YES];
[myArray sortUsingDescriptors:[NSArray arrayWithObjects:descriptor,nil]];
But my problem is that I want to sort only those arrays, which don’t contain empty birthday field. My array will contains several empty birthday fields. I don’t want to sort those.
Finally I have to load these in table view through [self.mTable reloadData];.
First collect the indices of all objetcs without a birthday.
NSIndexSet *indexSet = [NSIndexSet indexSet];
[array enumerateObjectsUsingBlock:^(NSDictionary *dict, NSUInteger idx, BOOL *stop)
{
if(![[dict allKeys] containsObject:#"birthday"]){
[indexSet addIndex:idx];
}
}];
Now remove them from the original array
[array removeObjectsAtIndexes:indexSet];
Using a comparator block, sorting could look like
[array sortUsingComparator: ^(NSDictionary *d1, NSDictionary *d2) {
NSDate *date1 = [d1 objectForKey:#"birthday"];
NSDate *date2 = [d2 objectForKey:#"birthday"];
return [date1 compare:date2]
}
Create a different array to back your table view like this:
NSDictionary* obj1 = [NSDictionary dictionaryWithObject: [NSDate date] forKey: #"birthday"];
NSDictionary* obj2 = [NSDictionary dictionaryWithObject: [NSDate dateWithTimeIntervalSince1970: 0] forKey: #"birthday"];
NSDictionary* obj3 = [NSDictionary dictionaryWithObject: #"wow" forKey: #"no_birthday"];
NSArray* all = [NSArray arrayWithObjects: obj1, obj2, obj3, nil];
NSArray* onlyWithBirthday = [all valueForKeyPath: #"#unionOfObjects.birthday"];
And if you need the full objects for the table view, continue with this code:
NSPredicate* filter = [NSPredicate predicateWithFormat: #"SELF.birthday IN %#", onlyWithBirthday];
NSArray* datasource = [all filteredArrayUsingPredicate: filter];
Then you can apply your sort method of choice.

Objective-C NSMutableArray: Organize array of photos by date key

I have an array of dictionaries..looks like this.
(
{name = somename;
date = NSDate;
other_params = some other params;
},
...
)
How can I then sort the array items by NSDate (oldest to newest or vice versa). Do I just do a basic select-sort algorithm or is there a shorter way?
You can sort the array using descriptors or using comparators, whatever you feel more comfortable with. Here is an example of using comparators:
NSArray *sortedArray = [myArray sortedArrayUsingComparator: ^(id obj1, id obj2) {
return [[obj1 date] compare:[obj2 date]];
}];
Here's the sort descriptors option:
// Adjust the 'ascending' option to invert the sort order.
NSSortDescriptor *dateSortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"date" ascending:YES];
// The sort descriptors have to go into an array.
NSArray *sortDescriptors = [NSArray arrayWithObject:dateSortDescriptor];
NSArray *sortedArray = [myArray sortedArrayUsingDescriptors:sortDescriptors];
You can also sort in place if you're using an NSMutableArray and don't need to keep its original order.

Sort NSArray of custom objects by their NSDate properties

I am attempting to sort an NSArray that is populated with custom objects. Each object has a property startDateTime that is of type NSDate.
The following code results in an array, sortedEventArray, populated but not sorted. Am I going about this the completely wrong way or am I just missing something small?
NSSortDescriptor *dateDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"startDateTime"
ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:dateDescriptor];
NSArray *sortedEventArray = [nodeEventArray sortedArrayUsingDescriptors:sortDescriptors];
Are you sure that the startDateTime instance variables of the node events are non-nil?
If you don't have one already, you might add a (custom) -description method to your node event objects that does something like this:
- (NSString *)description {
return [NSString stringWithFormat:#"%# - %#",
[super description], startDateTime]];
}
Then in your sorting code log the array before and after:
NSLog(#"nodeEventArray == %#", nodeEventArray);
NSSortDescriptor *dateDescriptor = [NSSortDescriptor
sortDescriptorWithKey:#"startDateTime"
ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:dateDescriptor];
NSArray *sortedEventArray = [nodeEventArray
sortedArrayUsingDescriptors:sortDescriptors];
NSLog(#"sortedEventArray == %#", sortedEventArray);
If the startDateTime's are all nil, then the before and after arrays will have the same order (since the sorting operation will equate to sending all the -compare: messages to nil, which basically does nothing).
Did you try by specifying the NSDate comparator?
Eg:
NSSortDescriptor *dateDescriptor = [NSSortDescriptor
sortDescriptorWithKey:#"startDateTime"
ascending:YES
selector:#selector(compare:)];
This should enforce the usage of the correct comparator of the NSDate class.
Ok, I know this is a little late, but this is how I would do it:
NSArray *sortedEventArray = [events sortedArrayUsingComparator:^NSComparisonResult(Event *event1, Event *event2) {
return [event1.startDateTime compare:event2.startDateTime];
}];
Obviously, replace Event with the class of your custom object. The advantage of this approach is that you are protected against future refactoring. If you were to refactor and rename the startDateTime property to something else, Xcode probably would not change the string you're passing into the sort descriptor. Suddenly, your sorting code would break/do nothing.
You can achieve like this,
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"anyDateField" ascending:YES];
NSMutableArray *arr = [[array sortedArrayUsingDescriptors:[NSArray arrayWithObjects:descriptor,nil]]mutableCopy];
You can achieve this like this,
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"date" ascending:FALSE];
[self.Array sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];

Sort NSArray of date strings or objects

I have an NSArray that contains date strings (i.e. NSString) like this: "Thu, 21 May 09 19:10:09 -0700"
I need to sort the NSArray by date. I thought about converting the date string to an NSDate object first, but got stuck there on how to sort by the NSDate object.
Thanks.
If I have an NSMutableArray of objects with a field "beginDate" of type NSDate I am using an NSSortDescriptor as below:
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"beginDate" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
Store the dates as NSDate objects in an NS(Mutable)Array, then use -[NSArray sortedArrayUsingSelector: or -[NSMutableArray sortUsingSelector:] and pass #selector(compare:) as the parameter. The -[NSDate compare:] method will order dates in ascending order for you. This is simpler than creating an NSSortDescriptor, and much simpler than writing your own comparison function. (NSDate objects know how to compare themselves to each other at least as efficiently as we could hope to accomplish with custom code.)
You may also use something like the following:
//Sort the array of items by date
[self.items sortUsingComparator:^NSComparisonResult(id obj1, id obj2){
return [obj2.date compare:obj1.date];
}];
But this does assume that the date is stored as a NSDate rather a NString, which should be no problem to make/do. Preferably, I recommend also storing the data in it's raw format. Makes it easier to manipulate in situations like this.
You can use blocks to sort in place:
sortedDatesArray = [[unsortedDatesArray sortedArrayUsingComparator: ^(id a, id b) {
NSDate *d1 = [NSDate dateWithString: s1];
NSDate *d2 = [NSDate dateWithString: s2];
return [d1 compare: d2];
}];
I suggest you convert all your strings to dates before sorting not to do the conversion more times than there are date items. Any sorting algorithm will give you more string to date conversions than the number of items in the array (sometimes substantially more)
a bit more on blocks sorting: http://sokol8.blogspot.com/2011/04/sorting-nsarray-with-blocks.html
What it worked in my case was the following:
NSArray *aUnsorted = [dataToDb allKeys];
NSArray *arrKeys = [aUnsorted sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"dd-MM-yyyy"];
NSDate *d1 = [df dateFromString:(NSString*) obj1];
NSDate *d2 = [df dateFromString:(NSString*) obj2];
return [d1 compare: d2];
}];
I had a dictionary, where all keys where dates in format dd-MM-yyyy. And allKeys returns the dictionary keys unsorted, and I wanted to present the data in chronological order.
You can use sortedArrayUsingFunction:context:. Here is a sample:
NSComparisonResult dateSort(NSString *s1, NSString *s2, void *context) {
NSDate *d1 = [NSDate dateWithString:s1];
NSDate *d2 = [NSDate dateWithString:s2];
return [d1 compare:d2];
}
NSArray *sorted = [unsorted sortedArrayUsingFunction:dateSort context:nil];
When using a NSMutableArray, you can use sortArrayUsingFunction:context: instead.
Once you have an NSDate, you can create an NSSortDescriptor with initWithKey:ascending: and then use sortedArrayUsingDescriptors: to do the sorting.
Swift 3.0
myMutableArray = myMutableArray.sorted(by: { $0.date.compare($1.date) == ComparisonResult.orderedAscending })
Change this
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"beginDate" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
To
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"Date" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
Just change the KEY: it must be Date always