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
对象进行排序

这可能吗?我该怎么做

更新

我现在尝试了以下方法

  • 我将一个可转换属性添加到我的用户对象中,在其中存储用户ID数组

  • 我尝试了以下排序描述符:

    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;
        }
    }