1

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

Community
  • 1
  • 1
Hazem Abdullah
  • 1,837
  • 4
  • 23
  • 41

3 Answers3

3

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.

DarkDust
  • 90,870
  • 19
  • 190
  • 224
Alexander Ney
  • 781
  • 3
  • 10
2

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.

Paul-Jan
  • 16,746
  • 1
  • 63
  • 95
1

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];
}];
DarkDust
  • 90,870
  • 19
  • 190
  • 224