web-dev-qa-db-fra.com

Quel est le moyen le plus efficace de trier un NSSet?

Quel est le moyen le plus efficace de trier des objets dans une variable NSSet/NSMutableSet en fonction d'une propriété des objets de l'ensemble? Pour le moment, je le fais en parcourant chaque objet, en l'ajoutant à un NSMutableArray et en triant ce tableau avec NSSortDescriptor.

63
Boon

essayez d'utiliser

[[mySet allObjects] sortedArrayUsingDescriptors:descriptors];

Edit : Pour iOS ≥ 4.0 et Mac OS X ≥ 10.6, vous pouvez utiliser directement

[mySet sortedArrayUsingDescriptors:descriptors];
114
cobbal

Le "moyen le plus efficace" de trier un ensemble d'objets varie en fonction de ce que vous voulez réellement dire. L'hypothèse fortuite (qui figure dans les réponses précédentes) est une sorte d'objets uniques dans un ensemble. Dans ce cas, je dirais que c'est à peu près tout ce qui se passe entre ce que @cobbal suggère et ce que vous avez proposé, ce qui ressemble probablement à ceci:

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

(Je dis que c'est un casse-tête, car l'approche de @ cobbal crée deux tableaux auto-édités, ce qui double l'encombrement de la mémoire. Ceci est sans importance pour les petits ensembles d'objets, mais techniquement, aucune approche n'est très efficace.)

Cependant, si vous triez les éléments de l'ensemble plusieurs fois (et surtout s'il s'agit d'une opération régulière), cette approche n'est certainement pas efficace. Vous pouvez conserver un tableau NSMutableArray et le maintenir synchronisé avec le NSSet, puis appeler -sortUsingDescriptors: à chaque fois, mais même si le tableau est déjà trié, il faudra tout de même effectuer N comparaisons.

Le cacao en soi ne fournit pas une approche efficace pour maintenir une collection dans un ordre trié. Java a une classe TreeSet qui gère les éléments dans un ordre trié chaque fois qu'un objet est inséré ou supprimé, contrairement à Cocoa. C'est précisément ce problème qui m'a amené à développer quelque chose de similaire pour mon propre usage.

Dans le cadre d’un framework de structures de données dont j’ai hérité et réorganisé, j’ai créé un protocole et quelques implémentations pour les ensembles triés . Chacune des sous-classes concrètes maintiendra un ensemble d'objets distincts dans un ordre trié. Il y a encore des améliorations à apporter - la principale étant qu'il trie en fonction du résultat de -compare: (que chaque objet de l'ensemble doit implémenter) et qu'il n'accepte pas encore de NSSortDescriptor. (Une solution de contournement consiste à implémenter -compare: comparer la propriété d'intérêt sur les objets.)

Un inconvénient possible est que ces classes ne sont (actuellement) pas des sous-classes de NS (Mutable) Set. Par conséquent, si vous devez passer un NSSet, il ne sera pas commandé. (Le protocole a une méthode -set qui retourne un NSSet, ce qui est bien sûr non ordonné.) Je prévois de corriger cela rapidement, comme je l'ai fait avec les sous-classes NSMutableDictionary dans le cadre. Les commentaires sont certainement les bienvenus. :-)

15
Quinn Taylor

Pour iOS ≥ 5.0 et Mac OS X ≥ 10.7, vous pouvez directement utiliser NSOrderedSet

8
bioffe

NSSet est une collection d'objets non ordonnés. En regardant les références Apple Les tableaux sont des collections ordonnées.

En examinant NSArray, vous trouverez des exemples de tri à l'adresse http://developer.Apple.com/documentation/Cocoa/Conceptual/Collections/Articles/sortingFilteringArrays ...

Exemple du lien:

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

Depuis OS X 10.7 et iOS 5.0, il existe NSOrderedSet. Vous pouvez l'utiliser pour conserver les objets dans leur ensemble et conserver leur ordre. NSMutableOrderedSet dispose de méthodes de tri . Dans certaines situations, cela peut améliorer les performances, car vous n'avez pas à créer d'objet séparé tel que NSArray pour stocker les éléments triés.

0
Andriy

Vous ne pouvez pas trier NSSet, car "rangArrayUsingFunction:" définit le résultat sous la forme NSArray ... Tous les indices supérieurs fonctionnent uniquement avec Array :)

NSArray *myArray = [mySet sortedArrayUsingDescriptors:descriptors];

Travailler parfait, et pas besoin d'autre moyen :)

0
iTux