使用内部对象的实例变量的值对自定义对象数组进行排序

Posted

技术标签:

【中文标题】使用内部对象的实例变量的值对自定义对象数组进行排序【英文标题】:Sorting array of custom objects using the value of an internal object's instance variable 【发布时间】:2012-01-30 10:13:07 【问题描述】:

(抱歉标题太长了)

我有一个自定义对象 Person,它又具有一个 NSSet,它有几个名为 Appointment 的自定义对象。因此,一个人可以有多个约会。约会的值是 startTime 和 endTime。

这些是 Core Data NSMangagedObject 类。

@interface Person : NSManagedObject

@property (nonatomic, retain) NSString *personName;
@property (nonatomic, retain) NSSet *appointments;

// etc

@end


@interface Appointment : NSManagedObject

@property (nonatomic, retain) NSNumber * startSecond;
@property (nonatomic, retain) NSNumber * endSecond;

// etc

@end

我如何获得人员列表,按照他们任何约会中最早的 startSecond 的顺序排列?

【问题讨论】:

可以参考***.com/questions/805547/…和***.com/questions/1066829/… 您可能应该创建一个自定义比较函数,该函数首先获取某人约会的最早日期。 (如果您每次都一个接一个地添加每个约会,那么您可能会保留一个保留最早时间的变量,只需检查具有最新最低时间的新约会)。然后你可以简单地比较:每个人和他们最早的日期相互比较,一个简单的日期比较。这对于 NSManagedObjects 也应该是可行的,因为它们继承自 NSObject。我可能可以给你写一个例子,但首先让我知道这是否是你所寻求的 有没有办法在不添加额外变量的情况下做到这一点? 【参考方案1】:

您可以使用排序描述符和 KVC 集合运算符:

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"appointments.@min.startSecond" ascending:YES];

例如,在 CoreData 提取中:

NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Person"];

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"appointments.@min.startSecond" ascending:YES];
[request setSortDescriptors:@[sortDescriptor]];

NSError *error = nil;
NSArray *sortedResults = [context executeFetchRequest:request error:&error];

或者只是排序一个数组:

NSArray *people = @[...];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"appointments.@min.startSecond" ascending:YES];

NSArray *sortedPeople = [people sortedArrayUsingDescriptors:@[sortDescriptor]];

有关 KVC 集合运算符的更多信息,请参阅KVC Programming Guide。

【讨论】:

如果您使用的是 Core Data,这就是您要走的路... +1 稍微解释一下:NSSortDescriptor 使用 Key-Value-Coding 访问它们排序所依据的值。所以你可以使用键“appointments.@min.startSecond”,这基本上意味着:在集合约会中,获取对象的startSecond,它的startSecond是集合中对象中最小的。然后它只是按返回值排序 NSFetchRequest 不允许使用这种描述符之王(“密钥路径包含不应该存在的 KVC 聚合”错误)。但可访问获取的结果。【参考方案2】:

如果你有 NSArray 形式的数据,你可以这样排序:

NSArray *sortedPersonArray = [coreDataPersonArray sortedArrayUsingSelector:@selector(compare:)];

- (NSComparisonResult)compare:(Person *)personObject 
    return [self.startSecond compare:personObject.startSecond];

【讨论】:

这非常适合我,因为我没有使用 CoreData。谢谢阿塔尼斯 NSSortDescriptorCoreData 没有绑定。您可以使用sortUsingDescriptors: 数组方法对带有NSSortDescriptor 的元素进行排序。【参考方案3】:

一个建议:

// Sorting key
NSString *key = @"startSecond";

// A mutable array version of your list of Persons.
NSMutableArray *a = [NSMutableArray arrayWithObjects:Person1, Person2, Person3, nil];

// Then use the sorted appointements to get your sorted person array.
[a sortUsingComparator:^NSComparisonResult(Person *p1, Person *p2) 
    NSSortDescriptor *sortDesc1 = [NSSortDescriptor sortDescriptorWithKey:key ascending:NO];
    NSArray *sortedApp1 = [p1.appointements sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDesc1]];

    NSSortDescriptor *sortDesc2 = [NSSortDescriptor sortDescriptorWithKey:key ascending:NO];
    NSArray *sortedApp2 = [p2.appointements sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDesc2]];

    return [[[sortedApp1 objectAtIndex:0] valueForKey:key] compare:[[sortedApp2 objectAtIndex:0] valueForKey:key]];

【讨论】:

对于返回语句的这一部分,我收到“空数组的索引 0 超出范围”错误:[sortedApp1 objectAtIndex:0] 这会很慢,因为它需要将所有约会对象拉入内存。

以上是关于使用内部对象的实例变量的值对自定义对象数组进行排序的主要内容,如果未能解决你的问题,请参考以下文章

如何按对象中的值对数组进行排序

是否可以根据这些对象的参数对自定义类对象列表进行子集化? (没有 LINQ)

ReactJS:如何根据道具的值对对象数组进行排序?

如何使用快速编码根据特定的排序顺序对自定义对象进行排序

按属性对自定义对象的 ArrayList 进行排序

根据对另一个 NSArray 字符串的排序,对自定义对象的 NSArray 进行排序