2012-11-20 6 views
6

Ich habe zwei NSArray Objekte, die ich gerne gleich sortiert werden würde. Einer enthält NSString Objekte, die anderen benutzerdefinierten Attribute Objekte. Hier ist, was meine "Schlüssel" NSArray wie folgt aussieht:Sortieren NSArray von benutzerdefinierten Objekten basierend auf der Sortierung eines anderen NSArray von Zeichenfolgen

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

The NSArray mit benutzerdefinierten Objekte:

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

Also, was würde Ich mag zu tun, verwenden Sie die stringOrder Array die Sortierung von zu bestimmen, das items Array von benutzerdefinierten Objekten. Wie kann ich das tun?

+0

Dies scheint nicht wie ein guter Ort um ein Array zu verwenden. Ein Wörterbuch oder ein geordnetes Wörterbuch könnte geeigneter und einfacher sein. – Alexander

Antwort

13

Hiermit vergleiche ich direkt den Index obj1.assetID in stringOrder mit dem Index von obj2.assetID in stringOrder (unter Verwendung von Objective-C-Literale für @() NSString => NSNumber zu verwandeln)

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

oder ohne ObjC Literale:

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

Ich bekomme nur eine "no visible @ Interface für NSArray deklariert Selektor sortUsingComparator:", wenn Sie dies tun. –

+0

Es ist verfügbar mit 10.6+ oder iOS 4.0+. Suchen Sie nach kompatiblen Lösungen? - (void) sortUsingComparator: (NSComparator) cmptr NS_AVAILABLE (10_6, 4_0); – cwehrung

+0

Sind Sie sicher, dass "items" wirklich als NSMutableArray (und nicht nur als NSArray) deklariert ist? – cwehrung

2

Es gibt ein paar Ansätze, die Sie ergreifen könnten.

Sie können Ihre Attributobjekte in einem NSDictionary speichern, wobei die Schlüssel die Zeichenfolgen in Ihrem stringOrder-Array sind. Dann könnten Sie ein sortiertes Array der Schlüssel bekommen und verwenden zu füllen, was Ansicht, die Sie verwenden, um sie anzuzeigen:

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

Die andere ist, dass Sie die Sortierreihenfolge eine intrinsische Eigenschaft des Attribut-Objekt machen, So kann ein Array von Attributen direkt sortiert werden. Ich würde diesen Ansatz nur empfehlen, wenn die Sortierreihenfolge tatsächlich eine intrinsische Eigenschaft Ihres Attributs-Objekts ist. Wenn dies nicht der Fall ist und Sie dies tun, werden Sie Präsentationsinformationen speichern, wo sie nicht hingehören.

Hier ist ein Beispiel:

NSArray* sortedAttrs = [attributes sortedArrayUsingComparator:^(id obj1, id obj2) { 
    // Perform comparison of Attribute's, ahem, attributes 
} 
+0

Also in Ihrem ersten Beispiel, wie würde das Wörterbuch basierend auf der AssetID-Eigenschaft meines Objekts sortieren? –

1

Hier ist die Lösung, die ich kam mit, dass sehr gut funktioniert. Jeder sieht Leistungsprobleme damit?

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

Während cwehrungs beantworten die Arbeit erledigt erhalten, ist die Leistung auf relativ kleine Arrays nicht groß.

Hier ist ein weiteres Verfahren für die gleiche Art von Art durchführen, die ein bisschen schneller ist (wenn auch bei weitem noch nicht perfekt):

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

Vergleich

Hier sind die Ergebnisse bilden, auf die beiden Methoden laufen ein iPhone 5:

sortUsingComparator:

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

Vorkonfektionierte Array

100 - 0.003 s 
1000 - 0.236 s 
2000 - 0.917 s 
3000 - 2.063 s 
0

Parallelverarbeitung:

Ergebnisse (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; 
} 
+0

Das 2. sortierte Ergebnis weicht von der Sortierzählung ab, da das Objekt nicht in sortby war – ssj

Verwandte Themen