I hava a core data application. And I want to fetch one kind of object, User
. User
have the property userId
.
I have another a
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];
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;
}];