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];
}];
Related
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];
}];
So I have the kind of classic situation where I want to group my tableView by Month/Year. I have a member of my conference object called beginDateSearchString that I use to put different conference into buckets; my problem is in the next part where I try and fail to use a NSSortDescriptor to sort each bucket by beginDate (which is a date).
I am getting an error related to unsorted not being able to receive sort descriptor type selectors.
Here is the disgusting code:
- (NSArray *)arrayOfDateSortedEvents {
NSMutableArray *sortedArray = [[NSMutableArray alloc] init];
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
//place into buckets
for (WSConference *conference in self.arrayOfEvents) {
if (![dictionary objectForKey:[conference beginDateSearchString]]) {
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:conference,nil];
[dictionary setObject:array forKey:[conference beginDateSearchString]];
}
else {
[[dictionary objectForKey:[conference beginDateSearchString]] addObject:conference];
}
}
//sort each bucket by descriptor beginDate
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"beginDate" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:descriptor];
for (NSMutableArray *unsorted in dictionary) {
[unsorted sortUsingDescriptors:sortDescriptors];
}
// now, unkey and add dictionary in order
while ([dictionary count] > 0) {
NSString *lowest = nil;
for (NSMutableArray *array in dictionary) {
if (!lowest)
lowest = [[dictionary allKeysForObject:array] objectAtIndex:0];
else {
if ([(WSConference *)[array objectAtIndex:0] beginDate] < [[dictionary objectForKey:lowest] beginDate])
lowest = [[dictionary allKeysForObject:array] objectAtIndex:0];
}
}
[sortedArray addObject:[dictionary objectForKey:lowest]];
[dictionary removeObjectForKey:lowest];
}
return sortedArray;
}
You want to probably filter the array in addition to sorting. See NSPredicate and the NSArray method -filteredArrayUsingPredicate: Then create an eventsByDateArray of the eventArrays created by the filter. Then in your table view delegate for creating the cells, if everything is ordered properly, the first section would represent the date of the events in the eventArray that is the first object of the eventsByDateArray and the table rows would consist of the events in the eventArray. And so on for each date.
Added
Your fast enumeration is incorrect. You enumerate through the keys of the dictionary. So in your code unsorted equals each of the keys as it enumerates. This is a GREAT lesson to everyone. It does not matter how you 'type' a variable. When Objective-C compiles it turns them all into id. So NSMutableArray *unsorted is not an NSMutableArray unless it is assigned to an NSMutableArray. If you assign unsorted to an NSString it will be an NSString. The fast enumerator for a dictionary works using the keys. So, in this case, unsorted becomes an NSString.
Instead of:
for (NSMutableArray *unsorted in dictionary) {
[unsorted sortUsingDescriptors:sortDescriptors];
}
you should have this:
for (id key in dictionary) {
NSMutableArray *unsorted = [dictionary objectForKey:key];
[unsorted sortUsingDescriptors:sortDescriptors];
}
I have an app which is retrieving its information from a plist.
The plist is an array of Dictionaries with the keys (author, cat, content).
Now I would like to show the categories in a table.
So I need all unique category entries in a sorted way.
I have successfully implemented following way but I am interested if this is the "right" solution.
Go through plist array and make new NSMutableArray with all category
entries of the dictionary
put this NSMutableArray into a NSSet to get unique Elements
put this NSSet into an NSArray to have the possibility to sort it.
return a NSMutableArray initiated with the sorted NSArray
I feel not , that this is the right way of doing so.
Any suggestions to do it better ?
Thanks a lot!
//InhaltefromWEb is a NSMutableArray
-(NSArray*) getCategories {
NSMutableArray* categorieTemp = [[NSMutableArray alloc] init];
unsigned count = [InhalteFromWeb count];
while (count--) {
NSString *tempString;
tempString=[[InhalteFromWeb objectAtIndex:count] objectForKey:CATEGORY];
NSLog(#"tempString %#", tempString );
[categorieTemp addObject:tempString];
}
NSSet *uniqueElements = [NSSet setWithArray:categorieTemp];
NSLog(#"categories from engine %#", categorieTemp);
NSArray* tempAr = [[[NSArray alloc] initWithArray:[uniqueElements allObjects]]sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
return [NSMutableArray arrayWithArray:tempAr];
}
Check for existing String with [categorieTemp containsObject:tempString] and sort it with [categorieTemp sortUsingComparator:...]
Example:
[categorieTemp sortUsingComparator:^NSComparisonResult(id obj1, id obj2)
{
return [(NSString *)obj1 caseInsensitiveCompare:(NSString *)obj2];
}];
I do this to sort my array for a date:
[array sortedArrayUsingComparator: ^(id obj1, id obj2) {
NSDate *date1 = [obj1 objectForKey:#"datum"] == nil ? nilDate : [obj1 objectForKey:#"datum"];
NSDate *date2 = [obj2 objectForKey:#"datum"] == nil ? nilDate : [obj2 objectForKey:#"datum"];
return (NSComparisonResult)[date2 compare: date1];
}];
For the purpose of asking this question about ordering. The following MyObject class returns an instance with random generated category names.
I use the following dataSource methods:
numberOfSections accessed with [dataSource count].
titleForSection accessed with [[dataSource objectAtIndex:indexPath.section] valueForKey:#"categoryName"].
numberOfRowsInSection accessed with [[[dataSource objectAtIndex:indexPath.section] valueForKey:#"myObjects"] count].
And finally, the MyObject for each row is accessed with [[[dataSource objectAtIndex:indexPath.section] valueForKey:#"myObjects"] objectAtIndex:indexPath.row] on the cellForRowAtIndexPath method.
I use the following code to create a dataSource that displays 9 section categories, however I'm a little stuck on the ordering of these categories and the data within. Assume there's an NSDate property as part of the MyObject class.
Question: How would I go about using this to display the records in descending order?
- (void)createDatasource
{
NSInteger numberOfObjects = 10;
NSMutableArray *objects = [NSMutableArray arrayWithCapacity:numberOfObjects];
NSMutableArray *categories = [NSMutableArray arrayWithCapacity:numberOfObjects];
for (int i = 0; i < numberOfObjects; i++)
{
MyObject *obj = [[MyObject alloc] init];
[objects addObject:obj];
[categories addObject:obj.category];
[obj release];
}
NSSet *set = [NSSet setWithArray:categories];
NSMutableArray *dataSource = [[NSMutableArray alloc] initWithCapacity:[set count]];
for (NSString *categoryString in set)
{
NSMutableDictionary *mainItem = [[NSMutableDictionary alloc] initWithObjectsAndKeys:nil, #"categoryName", nil, #"myObjects", nil];
NSMutableArray *mainItemMyObjects = [NSMutableArray array];
[mainItem setValue:categoryString forKey:#"categoryName"];
for (MyObject *obj in objects)
{
if ([obj.category isEqualToString:categoryString])
{
[mainItemMyObjects addObject:obj];
}
}
[mainItem setValue:mainItemMyObjects forKey:#"myObjects"];
[dataSource addObject:mainItem];
[mainItem release];
}
NSLog (#"objects = %#\ncategories = %#\nset = %#\ndatasource = %#", objects, categories, set, dataSource);
}
Easiest would be to sort your arrays, using NSMutableArray's sorting mutators or NSArray's sorting methods. Otherwise you'd have to construct some sort of mapping from input indices to dataSource indices for use by the various data source methods.
Edit Requested sample code for sorting, something like this should work. I assume you are wanting to sort everything by a property named date on the MyObject.
// First, sort the myObject mutable array in each category
for (NSDictionary *d in dataSource) {
[[d valueForKey:#"myObjects"] sortUsingComparator:^NSComparisonResult(id o1, id o2){
// Compare dates. NSDate's 'compare:' would do ascending order, so if we just
// reverse the order of comparison they'll come out descending.
return [[o2 date] compare:[o1 date]];
}];
}
// Second, sort the categories by the earliest dated object they contain
[dataSource sortUsingComparator:^NSComparisonResult(id o1, id o2){
// Extract the first object from each category's array, which must be the
// earliest it contains due to the previous sort.
MyObject *myObject1 = [[o1 valueForKey:#"myObjects"] objectAtIndex:0];
MyObject *myObject2 = [[o2 valueForKey:#"myObjects"] objectAtIndex:0];
// Compare dates, as above.
return [[myObject2 date] compare:[myObject1 date]];
}];
i have a NSDictionary and i get objects and keys in 'id' type format , with the following code:
NSDictionary *temp =[[NSDictionary alloc]initWithObjectsAndKeys:array1,#"array1",array2,#"array2",nil];
NSInteger count = [temp count];
id objects[count];
id keys[count];
[temp getObjects:objects andKeys:keys];
Where array1 and array2 are NSArrays.
Is there a way to convert id objects[n] to a NSArray ? (kind of pointless in this example cause array1 and array2 are already there , but this would be helpful in many ways)
Yes. Your array objects is C array, with count items in it. NSArray has an initializer that does what you need:
+ (id)arrayWithObjects:(const id *)objects count:(NSUInteger)count
So you would do
NSArray * myNewArray = [NSArray arrayWithObjects:objects count:count];
in this case.
Docs here.