Ios NSSortDescriptor-基于另一个数组的排序描述符
我有一个核心数据应用程序。我想获取一种对象,Ios NSSortDescriptor-基于另一个数组的排序描述符,ios,objective-c,cocoa-touch,core-data,nssortdescriptor,Ios,Objective C,Cocoa Touch,Core Data,Nssortdescriptor,我有一个核心数据应用程序。我想获取一种对象,UserUser具有属性userId 我有另一个带有userIds、[1,4,3,5]的数组。我想创建一个NSSortDescriptor,它根据数组中userIds的顺序对我的User对象进行排序 这可能吗?我该怎么做 更新 我现在尝试了以下方法 我将一个可转换属性添加到我的用户对象中,在其中存储用户ID数组 我尝试了以下排序描述符: sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"u
User
User
具有属性userId
我有另一个带有userId
s、[1,4,3,5]
的数组。我想创建一个NSSortDescriptor
,它根据数组中userId
s的顺序对我的User
对象进行排序
这可能吗?我该怎么做
更新
我现在尝试了以下方法
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"userId" ascending:YES comparator:^NSComparisonResult(id obj1, id obj2) {
NSUInteger idx1 = [self.user.followingIds indexOfObject:[obj1 valueForKey:@"userId"]];
NSUInteger idx2 = [self.user.followingIds indexOfObject:[obj2 valueForKey:@"userId"]];
return idx1 - idx2;
}];
Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. [<__NSCFNumber 0xa337400> valueForUndefinedKey:]: this class is not key value coding-compliant for the key userId. with userInfo {
NSTargetObjectUserInfoKey = 2502;
NSUnknownUserInfoKey = userId;
}
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFNumber 0xa337400> valueForUndefinedKey:]: this class is not key value coding- compliant for the key userId.'
严重的应用程序错误。在核心数据更改处理期间捕获异常。这通常是NSManagedObjectContextObjectsIDChangeNotification的观察者中的错误。[valueForUndefinedKey:]:此类不符合密钥用户标识的键值编码。使用userInfo{
NSTargetObjectUserInfoKey=2502;
NSUnknownUserInfoKey=userId;
}
***由于未捕获的异常“NSUnknownKeyException”而终止应用程序,原因:“[valueForUndefinedKey:]:此类不是键值编码-与键用户ID兼容。”
更新2
还要在用户
对象之间添加关系追随者
。你知道这种关系应该是什么样子吗?请参阅所附图片。对吗
如果消息id添加到数据库中,则使用我用来对其进行排序的方法
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"message_id" ascending:NO selector:@selector(localizedStandardCompare:)];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
request.returnsObjectsAsFaults=NO;
NSError *error = nil;
NSArray *results = [managedObjectContext executeFetchRequest:request error:&error];
这不能用排序描述符来完成,您必须在获取结果后应用自定义比较器函数:
NSArray *userIds = ...; // e.g. @[@1, @4, @3, @5]
NSArray *results = ...; // result of fetch request
NSArray *sorted = [results sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSUInteger idx1 = [userIds indexOfObject:[obj1 valueForKey:@"userId"]];
NSUInteger idx2 = [userIds indexOfObject:[obj2 valueForKey:@"userId"]];
return idx1 - idx2;
}];
正如@MartinR所说,排序描述符无法实现这一点。
要实现O(N)复杂度的可扩展解决方案(如果您真的需要):
//未测试
NSArray*排列=//@[@1、@4、@3、@5](用户ID);
NSMutableDictionary*map=[[NSMutableDictionary alloc]initWithCapacity:[置换计数]];
对于(整数i=0;i<[置换计数];++i){
map[permutation[i]]=@(i);
}
NSMutableArray*结果=//结果的可变副本
对于(整数i=0;i<[置换计数];){
id userId=[results[i]valueForKey:@“userId”];
NSUInteger key=[map[userId]unsignedIntegerValue];//我们希望该对象位于何处
如果(键!=i){
[结果交换objectatindex:i与objectatindex:key];
}否则{
++一,;
}
}
分析:(如果发现任何错误,请纠正我)映射阶段需要N个操作才能完成:O(N)
数组复制需要N次操作:O(N)
循环迭代N次,但:
它在最大N次交换时执行
和最大N比较
因此:O(N)+O(N)+O(N)+O(N)=4*O(N)=O(N)
@MartinR解决方案将基于一种基于比较的排序,该排序仅限于最小的O(N*lg(N))操作。
然而,每次比较都需要O(N)来获得第一个索引,O(N)来获得第二个索引。
因此:O(N*lg(N))*(O(N)+O(N))=2*O(N)*O(N*lg(N))=O((N^2)*lg(N))
对于足够小的N,没有实际的差异(N=10=>~40次运算用于我的解,约200次运算用于Martin的解)。
对于大型N,Martin的解决方案无法很好地扩展:
N==1000==>~4000个操作用于我的解决方案,~2*1000*1000*8=~16*10^6是否在数据库中存储用户ID。如果使用amit answer来完成此任务,那么localizedStandardCompare方法看起来如何?它将字符串相互比较。是否解决了您的问题?它在头文件NSString.h中定义。它看起来像是10.6中添加的/*localizedStandardCompare:,只要文件名或其他字符串出现在列表和表格中,并且类似查找器的排序是合适的,就应该使用它。此方法的确切行为可能会在将来的版本中进行调整,并且在不同的本地化下会有所不同,因此客户端不应依赖字符串的确切排序顺序。*/-(NSComparisonResult)本地化标准比较:(NSString*)字符串NS_可用(10_6,4_0);简单的解决方案是,当您将userId插入数据库时,请根据userIdArray将其插入,然后当您获得检索时,它会在存储排序后自动出现。谢谢,我已经尝试了您的解决方案,但无法完全使其工作。请参阅我的最新答案。有什么想法吗?@Anders:您在获取请求中使用过排序描述符吗?你不能那样做!在获取请求中不可能使用这样的排序描述符。您必须首先获取结果,然后按照我的回答中所述对其进行排序。-我也不知道为什么要使用可转换属性,这会使事情变得更复杂。@MartinR好的,你知道是否可以在NSFechResultController获取中“使用”结果吗?我在tableview中使用NSFechResultController作为我的数据源…@Anders:不,你不能对FRC的“FetchedObject”重新排序。-理论上,您可以在
cellforrowatinexpath
中的表视图行和FRC行之间进行“映射”。但是,FRC委托方法didChangeObject:…
也必须修改,因此这将是一个复杂的过程(这只是一个想法!)如果您确实需要无法使用内置sortdescriptor完成的自定义排序顺序,那么最好删除FRC。只需将结果提取到数组中并对其排序即可。如果有任何变化,请重新加载表视图。@MartinR谢谢,将尝试数组路由。while(key!=i){…}
循环对我来说很可疑,因为key
和i
都没有在循环体中被修改。现在它应该按照预期的方式进行。谢谢,这个解决方案的性能比@MartinR的好吗?这是怎么/为什么?现在看起来不错!当然,你是对的,我的解决方案不能很好地扩展。另一个O(N)解决方案是
//Not tested
NSArray* permutation = ...;//@[@1,@4,@3,@5] (user ids);
NSMutableDictionary* map = [[NSMutableDictionary alloc] initWithCapacity:[permutation count]];
for (NSUInteger i =0; i< [permutation count]; ++i) {
map[permutation[i]] = @(i);
}
NSMutableArray* results = ...;//A mutable copy of the results
for (NSUInteger i = 0; i < [permutation count];) {
id userId = [results[i] valueForKey:@"userId"];
NSUInteger key = [map[userId] unsignedIntegerValue];//where we like this object to be
if (key != i) {
[results exchangeObjectAtIndex:i withObjectAtIndex:key];
} else {
++i;
}
}