2009-07-01 8 views
62

Was ist die effizienteste Methode zum Sortieren von Objekten in einer /NSMutableSet basierend auf einer Eigenschaft der Objekte in der Menge? Genau jetzt mache ich es durch Iterieren durch jedes Objekt, füge sie zu einem NSMutableArray hinzu und sortiere dieses Array mit NSSortDescriptor.Wie kann ein NSSet am effizientesten sortiert werden?

Antwort

111

versuchen Sie es mit

[[mySet allObjects] sortedArrayUsingDescriptors:descriptors]; 

bearbeiten: Für iOS ≥ 4,0 und Mac OS X ≥ 10.6 direkt

[mySet sortedArrayUsingDescriptors:descriptors]; 
+0

Kurz und süß! – Boon

+5

Dies ist nicht viel anders als der Vorschlag des Fragestellers, und wahrscheinlich in etwa gleich in der Geschwindigkeit seit -allObjects gibt eine Autorelease NSArray, und -sortedArrayUsingDescriptors: gibt eine separate NSArray (beide sind unveränderlich). Die Kosten für das Zuweisen von zwei Arrays sind nicht viel weniger als das Aufzählen aller Elemente in einer (moderaten Größe) Menge und erfordert doppelt so viel Speicherplatz. –

+1

Es ist gut zu beachten, dass sortedArrayUsingDescriptors: eine nur 10.6-Methode ist. Wenn Sie auf 10.5 oder früher abzielen, sollten Sie vielleicht @ QuinnTaylors Ansatz ausprobieren. – Austin

2

NSSet ist eine Sammlung von ungeordneten Objekten. Betrachten von Apple-Referenzen Arrays sind geordnete Sammlungen.

bei NSArray der Suche gibt es eine Diskussion mit Beispielen von http://developer.apple.com/documentation/Cocoa/Conceptual/Collections/Articles/sortingFilteringArrays ...

Beispiel über den Link bei Sortierung:

NSInteger alphabeticSort(id string1, id string2, void *reverse) 
{ 
    if (*(BOOL *)reverse == YES) { 
     return [string2 localizedCaseInsensitiveCompare:string1]; 
    } 
    return [string1 localizedCaseInsensitiveCompare:string2]; 
} 

// assuming anArray is array of unsorted strings 

NSArray *sortedArray; 

// sort using a selector 
sortedArray = 
    [anArray sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; 

// sort using a function 
BOOL reverseSort = NO; 
sortedArray = 
    [anArray sortedArrayUsingFunction:alphabeticSort context:&reverseSort]; 
+3

Wow, dieser Apple-Beispielcode ist ziemlich schrecklich. Warum verwenden sie void *, NSInteger und int, wo es einfacher ist, ein BOOL zu verwenden? Warum sollte NSInteger anstelle von NSComparisonResult zurückgegeben werden? Ich bin mir sicher, dass es für die Kompatibilität mit früheren API-Entscheidungen ist, aber das ist verdammt hässlich! Ich empfehle, eine Selektor (Methode) anstelle einer Funktion zum Sortieren von Cocoa-Sammlungen zu verwenden - es ist einfacher und eleganter. –

+0

@QuinnTaylor Ich habe gerade überprüft und, ja, genug, die Dokumentation für 'sortedArrayUsingFunction: context:' sagt, dass die Funktion erwartet wird, zwei 'ID's und ein' void * 'zu nehmen und einen' NSInteger' zurückgeben. Zumindest ist die Probe korrekt. (Sie scheinen es auch aktualisiert zu haben - es saugt jetzt weniger.) –

15

Die „effizienteste Weg“ zu sortieren, eine Reihe von Objekten auf, was bedeutet, können variiert Sie tatsächlich. Die zufällige Annahme (die die vorherigen Antworten machen) ist eine einmalige Art von Objekten in einer Menge. In diesem Fall würde ich sagen, es ist ziemlich viel ein Wurf-up zwischen dem, was @cobbal legt nahe, und was kam man oben mit - wahrscheinlich in etwa wie folgt:

NSMutableArray* array = [NSMutableArray arrayWithCapacity:[set count]]; 
for (id anObject in set) 
    [array addObject:anObject]; 
[array sortUsingDescriptors:descriptors]; 

(ich sage, es ist ein Wurf-up weil @ cobbal Ansatz zwei Autoreleased Arrays erstellt, so verdoppelt sich der Speicherbedarf. Dies ist für kleine Gruppen von Objekten belanglos, aber technisch gesehen, ist weder Ansatz sehr effizient.)

jedoch, wenn Sie die Elemente zu sortier in das Set mehr als einmal (und vor allem, wenn es eine normale Sache ist) ist dies definitiv kein effizienter Ansatz. Sie könnten ein NSMutableArray in der Nähe halten und es mit dem NSSet synchronisieren und dann -sortUsingDescriptors: jedes Mal aufrufen, aber selbst wenn das Array bereits sortiert ist, werden immer noch N Vergleiche benötigt.

Cocoa allein bietet keinen effizienten Ansatz, um eine Sammlung in sortierter Reihenfolge zu verwalten. Java hat eine TreeSet Klasse, die die Elemente in sortierter Reihenfolge verwaltet, wann immer ein Objekt eingefügt oder entfernt wird, aber Cocoa nicht. Genau dieses Problem hat mich veranlasst, etwas Ähnliches für mich selbst zu entwickeln.

Als Teil eines Datenstrukturframeworks, das ich geerbt und überarbeitet habe, habe ich eine protocol and a few implementations for sorted sets erstellt. Jede der konkreten Unterklassen wird eine Reihe von verschiedenen Objekten in sortierter Reihenfolge beibehalten. Es gibt noch Verbesserungen, die man vornehmen muss - das wichtigste ist, dass es basierend auf dem Ergebnis von "compare" sortiert (was jedes Objekt in der Menge implementieren muss) und noch keinen NSSortDescriptor akzeptiert. (Eine Problemumgehung ist das Implementieren von compare: Vergleichen der Eigenschaft von Interesse für die Objekte.)

Ein möglicher Nachteil ist, dass diese Klassen (derzeit) keine Unterklassen von NS (Mutable) Set sind, also wenn Sie ein übergeben müssen NSSet, es wird nicht bestellt. (Das Protokoll hat eine -set-Methode, die ein NSSet zurückgibt, das natürlich ungeordnet ist.) Ich plane, dies bald zu korrigieren, wie ich es mit den Unterklassen NSMutableDictionary im Framework getan habe. Feedback ist auf jeden Fall willkommen.:-)

0

Sie können nicht NSSet sortieren, denn "sortedArrayUsingFunction:" gesetzt Ergebnis als NSArray ... und alle oberen Hinweis Arbeit mit nur Array :)

NSArray *myArray = [mySet sortedArrayUsingDescriptors:descriptors]; 

Arbeit perfekt, und nicht brauchen andere Art und Weise :)

8

Für iOS ≥ 5.0 und Mac OS X ≥ 10.7 Sie direkt NSOrderedSet

+0

Dies ist nicht t die Frage ansprechen, wo Sie ein vorhandenes NSSet haben und es sortieren wollen. – colincameron

0

Seit O X 10.7 und iOS 5.0 gibt es NSOrderedSet verwenden kann. Sie können damit Objekte im Satz behalten und ihre Reihenfolge beibehalten. NSMutableOrderedSet verfügt über Methoden zum Sortieren. In einigen Situationen kann dies zu einer Leistungsverbesserung führen, da Sie kein separates Objekt wie NSArray erstellen müssen, um sortierte Objekte zu speichern.

Verwandte Themen