我有一个自定义对象,其中包含基于时间段的信息,例如endCalYear,endMonth和periodLength属性,它们表示每个句点的结束及其长度。
我想创建一个基于NSSortDescriptor
或其他排序方法,它结合了这三个属性,并允许同时在所有三个键上对此对象进行排序。
示例:
EndCalYear endMonth periodLength (months) sortOrder
2012 6 6 1
2012 6 3 2
2012 3 3 3
2011 12 12 4
排序算法将完全根据我自己的算法自行决定。
我怎么能编写这样的算法?
基于块的sortDescriptorWithKey:ascending:comparator:
方法在我的视图中不起作用,因为它允许我只指定一个排序键。但是,我需要同时对所有三个键进行排序。
关于如何解决这个问题的想法或想法?
谢谢!
答案 0 :(得分:19)
您可以使用块进行排序:
NSArray *sortedArray;
sortedArray = [myArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
MyObject *first = (MyObject*)a;
MyObject *second = (MyObject*)b;
if (first.endCalYear < second.endCalYear) {
return NSOrderedAscending;
}
else if (first.endCalYear > second.endCalYear) {
return NSOrderedDescending;
}
// endCalYear is the same
if (first.endMonth < second.endMonth) {
return NSOrderedAscending;
}
else if (first.endMonth > second.endMonth) {
return NSOrderedDescending;
}
// endMonth is the same
if (first.periodLength < second.periodLength) {
return NSOrderedAscending;
}
else if (first.periodLength > second.periodLength) {
return NSOrderedDescending;
}
// periodLength is the same
return NSOrderedSame;
}]
按endCalYear
升序排序,然后endMonth
升序,最后periodLength
升序排序。您可以修改它以更改顺序或切换if语句中的符号以使其降序。
对于NSFetchedResultsController,您可能想尝试其他方法:
看起来你可以pass it a list of descriptors,每列需要排序一个:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSSortDescriptor *descriptor1 = [[NSSortDescriptor alloc] initWithKey:@"endCalYear" ascending:YES];
NSSortDescriptor *descriptor2 = [[NSSortDescriptor alloc] initWithKey:@"endMonth" ascending:YES];
NSSortDescriptor *descriptor3 = [[NSSortDescriptor alloc] initWithKey:@"periodLength" ascending:YES];
NSArray *sortDescriptors = @[descriptor1, descriptor2, descriptor3];
[fetchRequest setSortDescriptors:sortDescriptors];
答案 1 :(得分:7)
用于排序的API通常能够使用NSSortDescriptors
的数组,而不只是一个,所以为什么不使用它们呢?
例如,NSArray
有一个名为sortedArrayUsingDescriptors:
的方法(注意复数形式),它采用NSSortDescriptor
个对象的数组。
所以你可以简单地写一下:
NSSortDescriptor *endCalYearSD = [NSSortDescriptor sortDescriptorWithKey:@"endCalYear" ascending:YES];
NSSortDescriptor *endMonthSD = [NSSortDescriptor sortDescriptorWithKey:@"endMonth" ascending:YES];
NSSortDescriptor *periodLenSD = [NSSortDescriptor sortDescriptorWithKey:@"periodLength" ascending:YES];
NSArray *sortedArray = [originalArray sortedArrayUsingDescriptors:@[endCalYearSD, endMonthSD, periodLenSD]];
这样,你的originalArray
将首先被endCalYear排序,每个具有相同endCalYear的条目将按endMonth排序,每个具有相同endCalYear和endMonth的条目将按periodLendth排序。
对于大多数建议排序的API(包括CoreData等),您都有使用sortDescriptors数组的API,所以原则始终是相同的。
如果你真的只需要坚持一个NSSortDescriptor
(你的排序算法不够灵活,不能使用基于块的比较器或NSSortDescriptors
数组),你可以简单地提供一个属于自定义对象的属性,用于计算可以作为排序算法基础的值。
例如,将此类方法添加到自定义类:
-(NSUInteger)sortingIndex {
return endCalYear*10000 + endCalMonth*100 + periodLength;
}
然后对此键/属性进行排序。这不是一个非常干净的阅读和非常漂亮的设计模式,但更好的方法是改变你的排序算法API,允许一次排序多个键,所以......
我不明白为什么基于块的API sortDescriptorWithKey:ascending:comparator:
不适合你。你可以在那里指定你需要的任何自定义NSComparator
块,所以这个块可以告诉,给定两个对象,哪一个在另一个之前。您确定哪一个取决于您之前的方式,您只能比较endCalYear
或endCalYear
和endMonth
等,因此此处对使用多个排序没有限制密钥。