2009-07-01 27 views
62

¿Cuál es la forma más eficiente de ordenar objetos en un NSSet/NSMutableSet según una propiedad de los objetos en el conjunto? En este momento, la manera en que lo hago es iterando a través de cada objeto, agrégalos a un NSMutableArray y ordena esa matriz con NSSortDescriptor.¿Cuál es la forma más eficiente de ordenar un NSSet?

Respuesta

111

trate de usar

[[mySet allObjects] sortedArrayUsingDescriptors:descriptors]; 

Editar: Para iOS ≥ 4.0 y Mac OS X 10.6 ≥ puede utilizar directamente

[mySet sortedArrayUsingDescriptors:descriptors]; 
+0

¡Corto y dulce! – Boon

+5

Esto no es muy diferente de la sugerencia del asker, y probablemente más o menos equivalente en velocidad ya que -allObjects devuelve un NSArray liberado automáticamente, y -sortedArrayUsingDescriptors: devuelve un NSArray independiente (ambos son inmutables). El costo de asignar dos matrices no es mucho menos que enumerar todos los elementos en un conjunto (de tamaño moderado) y requiere el doble de espacio. –

+1

Es bueno tener en cuenta que sortedArrayUsingDescriptors: es solo un método 10.6. Si tiene como objetivo 10.5 o antes, puede probar el enfoque de @ QuinnTaylor – Austin

2

NSSet es una colección de objetos desordenados. Mirando las referencias de manzana Las matrices son colecciones ordenadas.

Mirando a NSArray hay una discusión de ejemplos de clasificación en http://developer.apple.com/documentation/Cocoa/Conceptual/Collections/Articles/sortingFilteringArrays ...

Ejemplo desde el enlace:

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

Guau, ese código de muestra de Apple en particular es bastante terrible. ¿Por qué están usando void *, NSInteger e int, donde es más sencillo usar un BOOL? ¿Por qué devolvería NSInteger en lugar de NSComparisonResult? Estoy seguro de que es compatible con las decisiones previas de la API, pero eso es feo. Sugiero usar un selector (método) en lugar de una función para ordenar colecciones de Cocoa: es más simple y más elegante. –

+0

@QuinnTaylor Acabo de verificar y, por supuesto, la documentación para 'sortedArrayUsingFunction: context:' dice que se espera que la función tome dos 'id's y un' void * 'y devuelva un' NSInteger'. En eso, al menos, la muestra es correcta. (Parece que también lo han actualizado, ahora es peor). –

15

La "forma más eficaz" para ordenar un conjunto de objetos varía en función de lo que realmente quiere decir. La suposición casual (que hacen las respuestas anteriores) es una especie de objetos de una sola vez en un conjunto. En este caso, yo diría que es más o menos un cara o cruz entre lo @cobbal sugiere y lo que le ocurrió - probablemente algo como lo siguiente:

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

(Yo digo que es un cara o cruz porque el enfoque de @ cobbal crea dos matrices autoreleased, por lo que se duplica la huella de memoria. Esto es intrascendente para pequeños grupos de objetos, pero técnicamente, ni el planteamiento es muy eficiente.)

sin embargo, si usted está ordenando los elementos de el set más de una vez (y especialmente si es algo normal) definitivamente este no es un enfoque eficiente. Puede mantener un NSMutableArray alrededor y mantenerlo sincronizado con el NSSet, luego llame a -sortUsingDescriptors: cada vez, pero incluso si el array ya está ordenado, aún necesitará N comparaciones.

El cacao en sí mismo simplemente no proporciona un enfoque eficiente para mantener una colección en orden ordenado. Java tiene una clase TreeSet que mantiene los elementos ordenados cada vez que se inserta o elimina un objeto, pero Cocoa no lo hace. Fue precisamente este problema el que me impulsó a desarrollar algo similar para mi propio uso.

Como parte de un marco de estructuras de datos que heredé y renové, creé un protocol and a few implementations for sorted sets. Cualquiera de las subclases concretas mantendrá un conjunto de objetos distintos en orden ordenado. Todavía hay mejoras que deben hacerse, la más importante es que se basa en el resultado de -compare: (que cada objeto en el conjunto debe implementar) y aún no acepta un NSSortDescriptor. (Una solución es implementar -compare: para comparar la propiedad de interés en los objetos.)

Una posible desventaja es que estas clases son (actualmente) no subclases de NS (Mutable) Set, por lo que si debe pasar un NSSet, no será ordenado. (El protocolo tiene un método -set que devuelve un NSSet, que por supuesto no está ordenado). Planeo rectificarlo pronto, como lo hice con las subclases NSMutableDictionary en el marco. La retroalimentación es definitivamente bienvenida.:-)

0

No puede ordenar NSSet, porque "sortedArrayUsingFunction:" set resultado como NSArray ... Y todo el trabajo de pista superior con solamente matriz :)

NSArray *myArray = [mySet sortedArrayUsingDescriptors:descriptors]; 

trabajo perfecto, y no necesitan otra manera :)

8

Para iOS ≥ 5.0 y Mac OS X 10.7 ≥ puede utilizar directamente NSOrderedSet

+0

Esto doesn ' t abordar la pregunta, dónde tienes un NSSet existente y quieres ordenarlo. – colincameron

0

Desde OS X 10.7 y el iOS 5.0 no NSOrderedSet. Puede usarlo para mantener los objetos en conjunto y mantener su orden. NSMutableOrderedSet tiene métodos para clasificar. En algunas situaciones, esto puede mejorar el rendimiento, ya que no es necesario crear un objeto separado como NSArray para almacenar elementos ordenados.

Cuestiones relacionadas