Hazem Abdullah
Hazem Abdullah

Reputation: 1903

What's the best way for custom sort to NSMutableArray that contains objects

I saw many examples for Custom sort for NSMutableArray , here one of them How to sort an NSMutableArray with custom objects in it?, but I have an object with a and b, and I want to sort them according to a*b.

I saw this code for example

NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthDate"
                                              ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors];

But I do not have birthDate here I need to sort according to a*b (both double)?

More details,

I have a NSMutableArray that contains CGRect objects, and I want to sort them according to width*height

Upvotes: 1

Views: 261

Answers (3)

Alexander Ney
Alexander Ney

Reputation: 781

I agree with the previous solutions. You can put CGRects in an array by wrapping them into an NSValue:

CGRect rect = CGRectMake(0, 10, 20, 30);
NSValue *valueToPutInArray = [NSValue valueWithCGRect:rect];

and sort them with a block like this:

NSArray *sortedArray = [rectArray sortedArrayUsingComparator:^NSComparisonResult(NSValue *rectAValue, NSValue *rectBValue) {
        CGRect rectA = [rectAValue CGRectValue];
        CGRect rectB = [rectBValue CGRectValue];

        CGFloat areaA = rectA.size.width * rectA.size.height;
        CGFloat areaB = rectB.size.width * rectB.size.height;

        if (areaA < areaB)
        {
            return NSOrderedAscending;
        }
        else if (areaB > areaA)
        {
            return NSOrderedDescending;
        }
        else
        {
            return NSOrderedSame;
        }
    }];

Another solution would be to wrap the CGRect into a custom object and add a function to it like

- (CGFloat)area
{
   return self.rect.size.width * self.rect.size.height;
}

(self.rect is the wrapped rect) If you populate your array with those custom objects you can sort it with your original method by creating a sort descriptor like

NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"area" ascending:YES];

This will simply compare the results of the area function and sort the array accruing to that.

Upvotes: 3

DarkDust
DarkDust

Reputation: 92384

The easiest way to implement custom sorting is to use -[NSMutableArray sortUsingComparator: or -[NSArray sortedArrayUsingComparator:].

sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    // Compare stuff, return a NSComparisonResult.
    return [obj1 compare:obj2];
}];

I like to explicitly pass the object types in the block, BTW. For example, for strings:

sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
    // Compare stuff, return a NSComparisonResult.
    return [obj1 localizedCaseInsensitiveCompare:obj2];
}];

Upvotes: 1

Paul-Jan
Paul-Jan

Reputation: 17278

A NSSortDescriptor is not suitable for anything more complex than comparing a simple key, or possibly a set of keys.

You'll want to sort using a custom comparator (a block). Something like

sortedArray = [myArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
    MyObject *first = (MyObject*)a;
    MyObject *second = (MyObject*)b;

    if (first.a * first.b < second.a * second.b) {
        return NSOrderedAscending;
    }
    else if (first.a * first.b > second.a * second.b) {
        return NSOrderedDescending;
    }
    return NSOrderedSame;
}]

Note I'm just winging it as far as your (a*b) description goes, not really sure what you want there.

Upvotes: 2

Related Questions