2

I am trying to figure out what the fastest/cleanest way to sort an array of CGPoints would be. I think I could achieve this using loops but that might not be the fastest and I hope it isn't the cleanest way. I would like to take an array of random CGPoints and sort them say by smallest x coordinate to largest, or smallest x and y coordinate to largest.

daveMac
  • 3,041
  • 3
  • 34
  • 59
  • It's possible to add them to a sorted structure? I think you can use a NSMutableArray and call method: - (void)insertObject:(id)anObject atIndex:(NSUInteger)index – Daniel Albert May 22 '12 at 19:09
  • I don't have any problem adding them (via NSValue) to an NSArray or NSMutableArray etc, I would like to know how to sort them or order them according to certain criteria. – daveMac May 22 '12 at 19:11

3 Answers3

9

After the correct comment by Chuck, I've updated the answer using the sortUsingComparator method:

Here is the complete code with sample data:

First we generate 100 random values that we enter to the Array:

NSMutableArray *testArray = [[NSMutableArray alloc] initWithCapacity:100];
for (int i=0; i<100; i++) {
    CGPoint testPoint = CGPointMake(arc4random()%100, arc4random()%100);
    [testArray addObject:[NSValue valueWithCGPoint:testPoint]];
}

and here is the actual code to sort the array:

[testArray sortUsingComparator:^(id firstObject, id secondObject) {
    CGPoint firstPoint = [firstObject CGPointValue];
    CGPoint secondPoint = [secondObject CGPointValue];
    return firstPoint.x>secondPoint.x;
}];

finally we can verify that the array was sorted, by printing it:

NSLog(@"%@",testArray);
Lefteris
  • 14,550
  • 2
  • 56
  • 95
  • 1
    NSSortDescriptor can't do anything with structs AFAIK. – Chuck May 22 '12 at 19:17
  • You are right Chuck, I've edited the answer to use the sortUsingComparator method – Lefteris May 22 '12 at 19:45
  • Just what I needed. But can you explain how that comparison is working? What exactly is it doing when it is returning "firstPoint.x>secondPoint.x"? – daveMac May 22 '12 at 20:59
  • It takes the objects in the array by 2 and compares them between them. If the first object is greater than the second, it moves the first object after the second, achieving a sort ascending. If you want a sort descending you need to compare the opposite, aka return firstPoint.xsecondPoint.x) return NSOrderedAscending; else if (firstPoint.x – Lefteris May 22 '12 at 21:20
3

The C qsort() function is probably your best bet if you just have a plain array of CGPoints. Something like this:

int compareXCoords(CGPoint *a, CGPoint *b) {
    return b->x - a->x;
}

// Later:

CGPoint points[100];
// initialize points somehow
qsort(points, 100, sizeof(CGPoint), compareXCoords);
// points is now sorted by the points' x coordinates
Chuck
  • 234,037
  • 30
  • 302
  • 389
  • A couple of things...how exactly is that formula working (b->x - a->x)? Also, my arrays are all objective-c and I would rather work with objects, just because I'm not real experienced in procedural c. Do I have to allocate and release the c arrays? – daveMac May 22 '12 at 19:22
  • 1
    @daveMac: The qsort callback is supposed to return an int indicating how the values should be ordered — any positive number means they're ascending, any negative number means they're descending, and 0 means equal. Subtracting the first number from the second does just that. As for how the points are stored: I thought you already *had* a C array. CGPoint is a C struct, so when you said you have an array of them, I assumed you meant a C array since there's no Cocoa collection that can actually store a CGPoint. If you have an NSMutableArray of NSValues, then Lefteris' answer is equivalent. – Chuck May 22 '12 at 21:09
  • 1
    Thanks Chuck, I appreciate the explanation. ...so much to learn all of the time. – daveMac May 22 '12 at 21:11
0

According to my comment, it's a good solution insert them on a NSMutableArray keeping the sort you decide.

You have to do something like this:

NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:1];

CGPoint candidate;
// Look for the position it has to be
int 0;
for (CGPoint point in array) {
    i++;
    // Compare candidate with current point
    // You have to define this condition, when point is greater than candidate
    if (point > candidate) {
        break;
    }
}
[array insertObjectAtIndex:i-1];

Maybe my code has some errors, I can't check if it's correct now.

Daniel Albert
  • 757
  • 5
  • 22