ios 如何对包含自定义对象的 NSMutableArray 进行排序?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/805547/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I sort an NSMutableArray with custom objects in it?
提问by rustyshelf
What I want to do seems pretty simple, but I can't find any answers on the web. I have an NSMutableArray
of objects, and let's say they are 'Person' objects. I want to sort the NSMutableArray
by Person.birthDate which is an NSDate
.
我想做的事情看起来很简单,但我在网上找不到任何答案。我有一个NSMutableArray
对象,假设它们是“人”对象。我想NSMutableArray
按 Person.birthDate排序,它是一个NSDate
.
I think it has something to do with this method:
我认为这与这种方法有关:
NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(???)];
In Java I would make my object implement Comparable, or use Collections.sort with an inline custom comparator...how on earth do you do this in Objective-C?
在 Java 中,我会让我的对象实现 Comparable,或者将 Collections.sort 与内联自定义比较器一起使用……你到底是如何在 Objective-C 中做到这一点的?
回答by Georg Sch?lly
Compare method
比较方法
Either you implement a compare-method for your object:
要么为对象实现比较方法:
- (NSComparisonResult)compare:(Person *)otherObject {
return [self.birthDate compare:otherObject.birthDate];
}
NSArray *sortedArray = [drinkDetails sortedArrayUsingSelector:@selector(compare:)];
NSSortDescriptor (better)
NSSortDescriptor(更好)
or usually even better:
或者通常更好:
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
ascending:YES];
NSArray *sortedArray = [drinkDetails sortedArrayUsingDescriptors:@[sortDescriptor]];
You can easily sort by multiple keys by adding more than one to the array. Using custom comparator-methods is possible as well. Have a look at the documentation.
您可以通过向数组添加多个键来轻松地按多个键排序。也可以使用自定义比较器方法。查看文档。
Blocks (shiny!)
块(闪亮!)
There's also the possibility of sorting with a block since Mac OS X 10.6 and iOS 4:
自 Mac OS X 10.6 和 iOS 4 起,还可以使用块进行排序:
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSDate *first = [(Person*)a birthDate];
NSDate *second = [(Person*)b birthDate];
return [first compare:second];
}];
Performance
表现
The -compare:
and block-based methods will be quite a bit faster, in general, than using NSSortDescriptor
as the latter relies on KVC. The primary advantage of the NSSortDescriptor
method is that it provides a way to define your sort order using data, rather than code, which makes it easy to e.g. set things up so users can sort an NSTableView
by clicking on the header row.
的-compare:
和基于块的方法将是相当快一点,一般来讲,除了使用NSSortDescriptor
作为后者依赖于KVC。该NSSortDescriptor
方法的主要优点是它提供了一种使用数据而不是代码来定义排序顺序的方法,这使得设置变得容易,例如,用户可以NSTableView
通过单击标题行进行排序。
回答by Alex Reynolds
See the NSMutableArray
method sortUsingFunction:context:
看NSMutableArray
方法sortUsingFunction:context:
You will need to set up a comparefunction which takes two objects (of type Person
, since you are comparing two Person
objects) and a contextparameter.
您将需要设置一个比较函数,它接受两个对象(类型为Person
,因为您正在比较两个Person
对象)和一个上下文参数。
The two objects are just instances of Person
. The third object is a string, e.g. @"birthDate".
这两个对象只是 的实例Person
。第三个对象是一个字符串,例如@"birthDate"。
This function returns an NSComparisonResult
: It returns NSOrderedAscending
if PersonA.birthDate
< PersonB.birthDate
. It will return NSOrderedDescending
if PersonA.birthDate
> PersonB.birthDate
. Finally, it will return NSOrderedSame
if PersonA.birthDate
== PersonB.birthDate
.
此函数返回一个NSComparisonResult
: 它返回NSOrderedAscending
if PersonA.birthDate
< PersonB.birthDate
。NSOrderedDescending
如果PersonA.birthDate
> ,它将返回PersonB.birthDate
。最后,它会返回NSOrderedSame
if PersonA.birthDate
== PersonB.birthDate
。
This is rough pseudocode; you will need to flesh out what it means for one date to be "less", "more" or "equal" to another date (such as comparing seconds-since-epoch etc.):
这是粗略的伪代码;您需要详细说明一个日期与另一个日期“更少”、“更多”或“相等”的含义(例如比较自纪元以来的秒数等):
NSComparisonResult compare(Person *firstPerson, Person *secondPerson, void *context) {
if ([firstPerson birthDate] < [secondPerson birthDate])
return NSOrderedAscending;
else if ([firstPerson birthDate] > [secondPerson birthDate])
return NSOrderedDescending;
else
return NSOrderedSame;
}
If you want something more compact, you can use ternary operators:
如果你想要更紧凑的东西,你可以使用三元运算符:
NSComparisonResult compare(Person *firstPerson, Person *secondPerson, void *context) {
return ([firstPerson birthDate] < [secondPerson birthDate]) ? NSOrderedAscending : ([firstPerson birthDate] > [secondPerson birthDate]) ? NSOrderedDescending : NSOrderedSame;
}
Inlining could perhaps speed this up a little, if you do this a lot.
如果您经常这样做,内联可能会加快速度。
回答by Chris
I did this in iOS 4 using a block. Had to cast the elements of my array from id to my class type. In this case it was a class called Score with a property called points.
我在 iOS 4 中使用块完成了此操作。必须将我的数组元素从 id 转换为我的类类型。在本例中,它是一个名为 Score 的类,具有一个名为 points 的属性。
Also you need to decide what to do if the elements of your array are not the right type, for this example I just returned NSOrderedSame
, however in my code I though an exception.
此外,您还需要决定如果数组的元素类型不正确该怎么办,对于这个例子,我刚刚返回NSOrderedSame
,但是在我的代码中,我虽然是一个例外。
NSArray *sorted = [_scores sortedArrayUsingComparator:^(id obj1, id obj2){
if ([obj1 isKindOfClass:[Score class]] && [obj2 isKindOfClass:[Score class]]) {
Score *s1 = obj1;
Score *s2 = obj2;
if (s1.points > s2.points) {
return (NSComparisonResult)NSOrderedAscending;
} else if (s1.points < s2.points) {
return (NSComparisonResult)NSOrderedDescending;
}
}
// TODO: default is the same?
return (NSComparisonResult)NSOrderedSame;
}];
return sorted;
PS: This is sorting in descending order.
PS:这是降序排列。
回答by leviathan
Starting in iOS 4 you can also use blocks for sorting.
从 iOS 4 开始,您还可以使用块进行排序。
For this particular example I'm assuming that the objects in your array have a 'position' method, which returns an NSInteger
.
对于这个特定的例子,我假设数组中的对象有一个“位置”方法,它返回一个NSInteger
.
NSArray *arrayToSort = where ever you get the array from... ;
NSComparisonResult (^sortBlock)(id, id) = ^(id obj1, id obj2)
{
if ([obj1 position] > [obj2 position])
{
return (NSComparisonResult)NSOrderedDescending;
}
if ([obj1 position] < [obj2 position])
{
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
};
NSArray *sorted = [arrayToSort sortedArrayUsingComparator:sortBlock];
Note: the "sorted" array will be autoreleased.
注意:“排序”数组将被自动释放。
回答by Fernando Redondo
I tried all, but this worked for me. In a class I have another class named "crimeScene
", and want to sort by a property of "crimeScene
".
我尝试了所有,但这对我有用。在一个类中,我有另一个名为“ crimeScene
”的类,并且想要按“ crimeScene
”的属性进行排序。
This works like a charm:
这就像一个魅力:
NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:@"crimeScene.distance" ascending:YES];
[self.arrAnnotations sortUsingDescriptors:[NSArray arrayWithObject:sorter]];
回答by Manuel Spuhler
There is a missing step in Georg Sch?lly's second answer, but it works fine then.
Georg Sch?lly 的第二个答案中有一个缺失的步骤,但它可以正常工作。
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate"
ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors];
// added the 's' because time was wasted when I copied and pasted and it failed without the 's' in sortedArrayUsingDescriptors
// 添加了 's' 因为当我复制和粘贴时浪费了时间,并且在 sortedArrayUsingDescriptors 中没有 's' 失败
回答by Hardik Darji
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"birthDate" ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors];
Thanks, it's working fine...
谢谢,它工作正常...
回答by freespace
Your Person
objects need to implement a method, say compare:
which takes another Person
object, and return NSComparisonResult
according to the relationship between the 2 objects.
你的Person
对象需要实现一个方法,比如compare:
哪个接受另一个Person
对象,并NSComparisonResult
根据两个对象之间的关系返回。
Then you would call sortedArrayUsingSelector:
with @selector(compare:)
and it should be done.
然后你会打电话sortedArrayUsingSelector:
给@selector(compare:)
,它应该完成。
There are other ways, but as far as I know there is no Cocoa-equiv of the Comparable
interface. Using sortedArrayUsingSelector:
is probably the most painless way to do it.
还有其他方法,但据我所知,没有 Cocoa-equiv 的Comparable
界面。使用sortedArrayUsingSelector:
可能是最无痛的方法。
回答by Kostiantyn Sokolinskyi
iOS 4 blocks will save you :)
iOS 4 块将拯救你:)
featuresArray = [[unsortedFeaturesArray sortedArrayUsingComparator: ^(id a, id b)
{
DMSeatFeature *first = ( DMSeatFeature* ) a;
DMSeatFeature *second = ( DMSeatFeature* ) b;
if ( first.quality == second.quality )
return NSOrderedSame;
else
{
if ( eSeatQualityGreen == m_seatQuality || eSeatQualityYellowGreen == m_seatQuality || eSeatQualityDefault == m_seatQuality )
{
if ( first.quality < second.quality )
return NSOrderedAscending;
else
return NSOrderedDescending;
}
else // eSeatQualityRed || eSeatQualityYellow
{
if ( first.quality > second.quality )
return NSOrderedAscending;
else
return NSOrderedDescending;
}
}
}] retain];
http://sokol8.blogspot.com/2011/04/sorting-nsarray-with-blocks.htmla bit of description
http://sokol8.blogspot.com/2011/04/sorting-nsarray-with-blocks.html一些描述
回答by DenTheMan
For NSMutableArray
, use the sortUsingSelector
method. It sorts it-place, without creating a new instance.
对于NSMutableArray
,使用sortUsingSelector
方法。它就地排序,无需创建新实例。