NSSortDescriptor - Sort descriptor based on another array

只谈情不闲聊 提交于 2019-12-01 06:28:22

This can not be done with a sort descriptor, you have to apply a custom comparator function after fetching the results:

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

As @MartinR said, you cannot do that with sort descriptors.
To achieve a scalable solution in O(N) complexity (if you really need it):

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

Analysis: (Please correct me if you spot any mistakes)

The mapping stage takes N operation to complete: O(N)
The array copy takes N operations: O(N)
The loop iterate N times, but:
it perform at max N exchanges
and at max N comparisons
hence: O(N) + O(N) + O(N) + O(N) = 4*O(N) = O(N)

@MartinR solution will be based on a comparison based sort limited to a minimum O(N*lg(N)) operations.
however each comparison takes O(N) to get the first index and O(N) to get the second index.
hence: O(N*lg(N))*(O(N) + O(N)) = 2*O(N)*O(N*lg(N)) = O((N^2)*lg(N))

For small enough N there is no real difference (N=10 ==> ~40 operations for my solution and ~200 operations for Martin's solution).
For large N Martin's solutions will not scale well:
N == 1000 ==> ~4000 operations for my solution and ~2*1000*1000*8 =~ 16*10^6

Use this idea which i use to sort message id if it is added to DB

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];
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!