Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort NSArray of custom objects based on sorting of another NSArray of strings

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?

like image 331
Nic Hubbard Avatar asked Nov 20 '12 09:11

Nic Hubbard


2 Answers

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]]]
}];
like image 192
cwehrung Avatar answered Sep 21 '22 13:09

cwehrung


While cwehrungs answer will get the job done, the performance is not great on relatively small arrays.

Here is another method for performing the same kind of sort that is a bit quicker (though still far from perfect):

NSMutableArray *sorted = [NSMutableArray array];

// pre-populate with objects
for (int i = 0; i < stringOrder.count; i++)
{
    [sorted addObject:[NSNull null]];
}
// place the items at the correct position
for (Attribute *a in items)
{
    NSUInteger idx = [stringOrder indexOfObject:a.assetID];
    if (idx != NSNotFound)
    {
        [sorted setObject:a atIndexedSubscript:idx];
    }
}
// finally remove all the unecesarry placeholders if one array was smaller
[sorted removeObject:[NSNull null]];

Comparison

Here are the results form running the two methods on an iPhone 5:

sortUsingComparator:

100  - 0.012 s
1000 - 1.116 s
2000 - 4.405 s
3000 - 9.028 s

prepopulated array

100 -  0.003 s
1000 - 0.236 s
2000 - 0.917 s
3000 - 2.063 s
like image 44
Nikola Lajic Avatar answered Sep 21 '22 13:09

Nikola Lajic