How to make collection operators respect the controller's sort descriptor?

113 views Asked by At

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?

1

There are 1 answers

8
Martin R On BEST ANSWER

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