Cocoa has this concept of collection operators that allow to return a set of objects based on a property. In my array controller I have a number of objects that are executed on a specific date and I want to process them in some way. So I retrieve a list of unique execution dates with this code:
NSArray *assignments = categoryAssignments.arrangedObjects;
NSArray* distinctDates = [assignments valueForKeyPath: @"@distinctUnionOfObjects.dayOfExecution"];
However, the order in that array does not follow the order in the arrangedObjects array (the dates are sorted descending, while the distinctDates array is sorted ascending).
Is there a way to make the collection operator respect the array controller's sort descriptor?
@distinctUnionOfObjects
has to work with arbitrarily (unsorted) input data.
The input data might even (as @Kevin correctly commented) contain objects that
are not comparable at all.
It could be that @distinctUnionOfObjects
uses a NSMutableSet
internally to find a list
of unique objects (and the objects in a set do not have a defined order). But that
is pure speculation and does not help.
It is simply not documented that the output of @distinctUnionOfObjects
preserves any order of the input data, and I do not know any parameter to enforce that.
Therefore you have to sort the returned list according to your requirements.
Alternatively, you could replace valueForKeyPath:...
by the following code
which preserves the order of the elements. The code uses a NSMutableSet
to keep track
of all elements added to the result array so far, because testing for membership
is faster with sets as with arrays.
NSArray *assignments = categoryAssignments.arrangedObjects;
NSMutableSet *found = [NSMutableSet set];
NSMutableArray *distinctDates = [NSMutableArray array];
for (NSDictionary *obj in objects) {
NSDate *date = obj[@"dayOfExecution"];
if (![found containsObject:date]) {
[distinctDates addObject:date];
[found addObject:date];
}
}