简体   繁体   English

根据另一个NSArray字符串的排序对自定义对象的NSArray进行排序

[英]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. 我有两个NSArray对象,我希望对它们进行相同的排序。 One contains NSString objects, the other custom Attribute objects. 一个包含NSString对象,另一个包含自定义Attribute对象。 Here is what my "key" NSArray looks like: 这是我的“关键”NSArray的样子:

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

The NSArray with custom objects: 带有自定义对象的NSArray:

// 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. 所以,我想要做的是使用stringOrder数组来确定自定义对象的items数组的排序。 How can I do this? 我怎样才能做到这一点?

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) 在此,我直接比较stringOrder中obj1.assetID的索引和stringOrder中obj2.assetID的索引(使用@()的Objective-C文字来转换NSString => NSNumber)

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

Or without ObjC literals : 或者没有ObjC文字:

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

While cwehrungs answer will get the job done, the performance is not great on relatively small arrays. 虽然cwehrungs的答案将完成工作,但在相对较小的阵列上性能并不高。

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: 以下是在iPhone 5上运行这两种方法的结果:

sortUsingComparator: 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

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. 您可以将属性对象存储在NSDictionary中,其中键是stringOrder数组中的字符串。 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. 另一个是您将排序顺序作为Attribute对象的固有属性,因此可以直接对Attributes数组进行排序。 I would only recommend taking this approach if the sort order is actually an intrinsic property of your Attributes object. 如果排序顺序实际上是Attributes对象的固有属性,我只建议采用这种方法。 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
}

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];

Parallel Processing: 并行处理:

Results (quad core): 结果(四核):

 1. sortme:95    sortby:852345 sorted:95    time:0.052576
 2. sortme:54248 sortby:852345 sorted:54243 time:0.264660





-(NSArray *)sortArray:(NSArray *)sortme sortBy:(NSArray *)sortBy{

CFAbsoluteTime time = CFAbsoluteTimeGetCurrent();

NSSet *sortmeSet = [NSSet setWithArray:sortme];

NSMutableDictionary *sortDictionary = [NSMutableDictionary dictionary];
dispatch_queue_t sortDictionaryThread = dispatch_queue_create("my.sortDictionaryThread", DISPATCH_QUEUE_CONCURRENT);

[sortBy enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

    if ([sortmeSet containsObject:obj]){
        dispatch_barrier_async(sortDictionaryThread, ^{
            sortDictionary[obj] = @(idx);
        });
    }
}];


__block NSArray *sortedArray = nil;
dispatch_barrier_sync(sortDictionaryThread, ^{
    sortedArray = [sortDictionary keysSortedByValueUsingSelector:@selector(compare:)];
});

NSLog(@"sortme:%li sortby:%li sorted:%li time:%f",sortme.count,sortBy.count,sortedArray.count, CFAbsoluteTimeGetCurrent() - time);

return sortedArray;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM