NSSortDescriptor:同时对多个键进行自定义比较
我有一个自定义对象,其中包含基于时间段的信息,例如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:
方法在我的视图中不起作用,因为它允许我只指定一个排序键。 但是,我需要同时对所有三个键进行排序。
关于如何解决这个问题的想法或想法?
谢谢!
您可以使用块进行排序:
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,您可能想尝试其他方法:
看起来您可以在其中输入一个描述符列表,每个列对应一个要排序的列:
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];
用于排序的API通常能够使用NSSortDescriptors
数组,而不仅仅是一个,所以为什么不使用它们呢?
例如, NSArray
有一个名为sortedArrayUsingDescriptors:
的方法sortedArrayUsingDescriptors:
注意复数forms),它采用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为大多数建议排序的API(包括CoreData等)使用sortDescriptors数组,因此原则始终相同。
如果你真的只需要坚持使用一个NSSortDescriptor
(并且你的排序算法不够灵活,不能使用基于块的比较器或NSSortDescriptors
数组),你可以简单地为自定义对象提供一个属性来计算某个值。你可以根据你的排序算法。
例如,将此方法添加到您的自定义类:
-(NSUInteger)sortingIndex { return endCalYear*10000 + endCalMonth*100 + periodLength; }
然后对此键/属性进行排序。 这不是一个非常干净的阅读和一个非常漂亮的设计模式,但更好的方法是改变你的排序算法API,允许一次排序多个键,所以……
[编辑] (回答基于块的API的[编辑])
我不明白为什么基于块的API sortDescriptorWithKey:ascending:comparator:
将不适合你。 您可以在那里指定所需的任何自定义NSComparator
块,因此,对于两个对象,此块可以告诉您哪一个在另一个之前。 您确定哪一个取决于您之前的方式,您只能比较endCalYear
, endCalYear
和endMonth
等,因此这里没有限制使用多个键进行排序。