Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have two NSArray objects that I would like to be sorted the same. One contains NSString objects, the other custom Attribute objects. Here is what my "key" NSArray looks like:

// The master order
NSArray *stringOrder = [NSArray arrayWithObjects:@"12", @"10", @"2", nil];

The NSArray with custom objects:

// The array of custom Attribute objects that I want sorted by the stringOrder array
NSMutableArray *items = [[NSMutableArray alloc] init];
Attribute *attribute = nil;

attribute = [[Attribute alloc] init];
attribute.assetID = @"10";
[items addObject:attribute];

attribute = [[Attribute alloc] init];
attribute.assetID = @"12";
[items addObject:attribute];

attribute = [[Attribute alloc] init];
attribute.assetID = @"2";
[items addObject:attribute];

So, what I would like to do is use the stringOrder array to determine the sorting of the items array of custom objects. How can I do this?

share|improve this question
    
This doesn't seem like a good place to use an array. A dictionary or ordered dictionary might be more appropriate, and easier. –  XAleXOwnZX 14 hours ago

3 Answers 3

up vote 5 down vote accepted

Hereby, I compare directly the index of obj1.assetID in stringOrder with the index of obj2.assetID in stringOrder (using Objective-C literals for @() to transform NSString => NSNumber)

[items sortUsingComparator:^NSComparisonResult(Attribute *obj1, Attribute *obj2) {
    return [@([stringOrder indexOfObject:obj1.assetID]) compare:@([stringOrder indexOfObject:obj2.assetID])]
}];

Or without ObjC literals :

[items sortUsingComparator:^NSComparisonResult(Attribute *obj1, Attribute *obj2) {
    return [[NSNumber numberWithInt:[stringOrder indexOfObject:obj1.assetID]] compare:[NSNumber numberWithInt:[stringOrder indexOfObject:obj2.assetID]]]
}];
share|improve this answer
    
I just get a "no visible @interface for NSArray declares selector sortUsingComparator:" when doing this. –  Nic Hubbard Nov 20 '12 at 17:10
    
It's available with 10.6+ or iOS 4.0+. Are you looking for more compatible solutions ? - (void)sortUsingComparator:(NSComparator)cmptr NS_AVAILABLE(10_6, 4_0); –  cwehrung Nov 20 '12 at 18:00
    
Are you sure "items" is really declared as a NSMutableArray (and not only an NSArray) ? –  cwehrung Nov 20 '12 at 18:01
    
Yes it is. I got it working though, works great!! –  Nic Hubbard Nov 20 '12 at 18:52
    
This has terrible performance implications since calling indexOfObject (a linear search) on each comparison reduces the sort to O(n²). You would be better off zipping the arrays and sorting the result, or even creating a dictionary from assetIds to their index in the other array –  axelarge Feb 7 at 11:16

There are a couple approaches you could take.

You could store your Attribute objects in an NSDictionary, with the keys being the strings in your stringOrder array. Then, you could get a sorted array of the keys and use that to populate whatever view you're using to display them:

NSArray* sortedKeys = [dict keysSortedByValueUsingComparator:^(id obj1, id obj2) {
    return [obj1 compareTo:obj2];
}

The other is that you make the sort order an intrinsic property of your Attribute object, so an array of Attributes can be sorted directly. I would only recommend taking this approach if the sort order is actually an intrinsic property of your Attributes object. If it isn't and you do this, you'll wind up storing presentation information where it doesn't belong.

Here's an example:

NSArray* sortedAttrs = [attributes sortedArrayUsingComparator:^(id obj1, id obj2) {
    // Perform comparison of Attribute's, ahem, attributes
}
share|improve this answer
    
So in your first example, how would the dictionary know to sort based on the assetID property of of my object? –  Nic Hubbard Nov 20 '12 at 16:23

Here is the solution that I came up with that works extremely well. Anyone see performance issues with this?

for (Attribute *a in items) {
    int index = [stringOrder indexOfObject:a.assetID];
    a.sortOrder = index;
}

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"sortOrder" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [items sortedArrayUsingDescriptors:sortDescriptors];
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.