Anton Unt
Anton Unt

Reputation: 1875

Sorting an NSArray of Objects WRT the objects contained in NSSet in those objects

So here is the hierarchy:

NSArray A contains 3 objects. Each of those custom objects contains an NSSet of another custom objects. Each of those "another custom object"s contains a number.

I want to sort NSArray A by that number. I would not care of what object in the set was picked up. Any object from that set would be fine.

Any clues on how to do it with NSSortDescriptor?

Upvotes: 2

Views: 263

Answers (2)

Martin R
Martin R

Reputation: 539955

Key-Value coding works also with properties (or even instance variables) of custom objects, as shown in the following example. But you have to specify a collection operator that is applied to the set to choose an object for sorting, e.g. @max, @min or @avg.

// The "inner object", containing a number:
@interface Custom1 : NSObject
@property (nonatomic, strong) NSNumber *number;
@end

@implementation  Custom1
@end

// The "outer object", containing a set of "inner" objects:
@interface Custom2 : NSObject
@property (nonatomic, strong) NSSet *others; // set of "Custom1 objects.
@end

@implementation  Custom2
@end

Now you can do the following:

Custom1 *o1 = [[Custom1 alloc] init];
o1.number = @1;
Custom1 *o2 = [[Custom1 alloc] init];
o2.number = @2;
Custom2 *p1 = [[Custom2 alloc] init];
p1.others = [NSSet setWithObjects:o1, o2, nil];

Custom1 *o3 = [[Custom1 alloc] init];
o3.number = @3;
Custom1 *o4 = [[Custom1 alloc] init];
o4.number = @4;
Custom2 *p2 = [[Custom2 alloc] init];
p2.others = [NSSet setWithObjects:o3, o4, nil];

NSArray *array = @[p1, p2];

// Sort according to maximum number in the inner object set:
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"[email protected]" ascending:YES];
NSArray *sortedArray = [array sortedArrayUsingDescriptors:@[sort]];

Upvotes: 3

Monolo
Monolo

Reputation: 18253

Since the data are stored in an NSArray the sort can be done using blocks, known to a sort descriptor as a comparator. Note that this approach does not work with SQLite-backed Core Data fetches, which sort directly on the property value stored in the underlying data base.

There are several ways to go about it, this one is straight forward, bordering on the pedestrian (and I hope I got the data structure right):

NSArray *data = @[
    @{@"otherobjects":[NSSet setWithObjects: @{@"num":@2}, @{@"num":@1}, @{@"num":@4}, nil]},
    @{@"otherobjects":[NSSet setWithObjects:@{@"num":@7}, @{@"num":@9}, @{@"num":@8}, nil]}
];

NSSortDescriptor *sd = [NSSortDescriptor sortDescriptorWithKey:@"otherobjects" ascending:NO comparator:^NSComparisonResult(id obj1, id obj2) {

    NSNumber *n1 = [[obj1 anyObject] valueForKey:@"num"];
    NSNumber *n2 = [[obj2 anyObject] valueForKey:@"num"];
    return [n1 compare: n2];
}];

NSArray *sorted = [data sortedArrayUsingDescriptors:@[sd]];

If you want to get fancy, you can implement a method on your custom object which compares two objects, and then create a sort descriptor using that method, or you could declare a read-only property returning for instance the max or min value of the NSSet, and then simply use a normal sort descriptor on that property.

Upvotes: 2

Related Questions