Quand est-il préférable d'utiliser un NSSet sur un NSArray?

112

J'ai utilisé NSSets plusieurs fois dans mes applications, mais je n'en ai jamais créé moi-même.

Quand est-il préférable d'utiliser un NSSetplutôt que un NSArrayet pourquoi?

geminiCoder
la source

Réponses:

173

Lorsque l'ordre des éléments de la collection n'est pas important, les ensembles offrent de meilleures performances pour rechercher des éléments de la collection.

La raison en est qu'un ensemble utilise des valeurs de hachage pour trouver des éléments (comme un dictionnaire) tandis qu'un tableau doit parcourir tout son contenu pour trouver un objet particulier.

Ole Begemann
la source
9
log (1) vs log (n)
rohan-patel
25
@ rohan-patel Correct est O (1) vs O (n)
Mansurov Ruslan
1
Si commandé: O (1) vs O (logn) puisque la recherche binaire est applicable. Si non ordonné, alors O (1) vs O (n)
baskInEminence
180

L'image de la documentation Apple le décrit très bien:

Collections Objective-C

Arrayest une séquence ordonnée (l'ordre est conservé lorsque vous ajoutez)

[array addObject:@1];
[array addObject:@2];
[array addObject:@3];
[array addObject:@4];
[array addObject:@6];
[array addObject:@4];
[array addObject:@1];
[array addObject:@2];

[1, 2, 3, 4, 6, 4, 1, 2]

Setest une liste d'éléments distincts (pas de doublons) et non ordonnés

[set addObject:@1];
[set addObject:@2];
[set addObject:@3];
[set addObject:@4];
[set addObject:@6];
[set addObject:@4];
[set addObject:@1];
[set addObject:@2];

[1, 2, 6, 4, 3]
James Webster
la source
2
Dans votre exemple, vous ajoutez des primitives à un tableau et à un ensemble. Ni l'un ni l'autre n'est possible car ils ne peuvent contenir que des objets.
FreeAsInBeer
10
Merci pour votre modification @Zaheer, mais elle était en fait invalide. Je n'ajoutais pas de primitifs. J'ajoutais des littéraux.
James Webster
Excellente explication :) +1 :)
Karun
1
Aimez votre explication! +1 pour cela
rébellion
66

La meilleure réponse est à cela est la propre documentation d'Apple .

entrez la description de l'image ici

La principale différence est qu'il NSArrays'agit d'une collection ordonnée et NSSetd'une collection non ordonnée.

Il existe plusieurs articles qui parlent de la différence de vitesse entre les deux, comme celui-ci . Si vous parcourez une collection non ordonnée, NSSetc'est génial. Cependant, dans de nombreux cas, vous devez faire des choses que seul un NSArraypeut faire, vous sacrifiez donc la vitesse pour ces capacités.

NSSet

  • Accédez principalement aux éléments par comparaison
  • Non ordonné
  • N'autorise pas les doublons

NSArray

  • Peut accéder aux éléments par index
  • Commandé
  • Permet les doublons

C'est tout ce qu'il y a vraiment à faire! Faites-moi savoir si cela vous a été utile.

woz
la source
Vous n'avez pas à toujours sacrifier NSSetpour l'indexation. Il est courant d'utiliser deux structures de données différentes pour les mêmes données. Ou vous construisez et indexez sur ce tableau :) Mais alors il est préférable d'utiliser une base de données qui l'a déjà implémentée.
Sulthan
"Construisez un index sur ce tableau". Vous ne pouvez pas créer d'index sur un NSSet. Il existe de nombreuses techniques différentes que vous pouvez utiliser. Et si vous devez faire des sacrifices à LA FOIS en termes de mémoire et de puissance de traitement, alors vous le faites mal.
Sulthan
Puisque la question porte sur NSSetet NSArray, ma réponse est exacte et complète. Oui, vous pouvez créer d'autres structures de données, mais je compare simplement ces deux.
woz
J'ai voté pour mais votre réponse est incorrecte lorsque vous parlez de sacrifices. Si vous avez besoin de certaines fonctionnalités NSArrayet de certaines fonctionnalités de NSSet, la bonne réponse n'est pas "utiliser NSArrayet sacrifier les performances". La réponse est de combiner les deux ou d'utiliser une structure de données différente.
Sulthan
J'aurais dit que la principale différence est définie pour les objets uniques où un tableau peut avoir des doublons. L'aspect ordre est secondaire à ce fait.
malhal
12

NSOrderedSet est disponible dans iOS 5+, donc la principale différence est de savoir si vous voulez des objets en double dans la structure de données.

Jason
la source
9

NSArray :

  1. Collecte ordonnée de données
  2. Permet les doublons
  3. C'est un objet de type collection

NSSet :

  1. Collecte non ordonnée de données
  2. N'autorise pas les doublons
  3. C'est aussi un objet de type collection
Vie iOS
la source
7

Un tableau est utilisé pour accéder aux éléments par leur index. Tout élément peut être inséré dans le tableau plusieurs fois. Les tableaux conservent l'ordre de leurs éléments.

Un ensemble est essentiellement utilisé uniquement pour vérifier si l'élément est dans la collection ou non. Les articles n'ont aucune notion de commande ou d'indexation. Vous ne pouvez pas avoir un élément dans un ensemble deux fois.

Si un tableau veut vérifier s'il contient un élément, il doit vérifier tous ses éléments. Les ensembles sont conçus pour utiliser des algorithmes plus rapides.

Vous pouvez imaginer un ensemble comme un dictionnaire sans valeurs.

Notez que tableau et ensemble ne sont pas les seules structures de données. Il y en a d'autres, par exemple Queue, Stack, Heap, Fibonacci's Heap. Je recommanderais de lire un livre sur les algorithmes et les structures de données.

Voir wikipedia pour plus d'informations.

Sulthan
la source
En fait, un tableau n'a besoin d'être vérifié que jusqu'au point où l'élément est trouvé. Si l'élément EST dans le tableau, il sera très rarement nécessaire de vérifier chaque élément.
FreeAsInBeer
Oui, comme vous dites "si l'élément EST dans le tableau". Si vous vous attendez à cela, vous n'avez pas à vérifier si c'est là ou non. La complexité de l' containsopération est O(n). Le nombre de comparaisons lorsqu'il n'est pas dans le tableau est n. Le nombre moyen de comparaisons lorsque l'objet est dans le tableau est n/2. Même si l'objet est trouvé, les performances sont horribles.
Sulthan
Les performances ne seraient horribles qu'avec une large gamme. Si vous saviez que la baie pouvait devenir assez volumineuse, il existe des moyens d’améliorer les performances de la baie, par exemple en utilisant une baie de baies.
FreeAsInBeer
Si l'opération d'égalité est coûteuse, vous verrez la différence même sur des tableaux avec 3 éléments. Et le même comportement qu'un grand tableau peut se produire lorsque vous répétez souvent l'opération (par exemple, utilisez l'opération dans un cycle «pour»). Avez-vous entendu parler de la complexité amortie? La complexité est toujours linéaire et les performances sont affreuses par rapport à un ensemble (généralement avec une complexité constante).
Sulthan
Évidemment, il y aura une différence, je dis simplement que la notation big o est exponentielle; avec de petits tableaux, la différence sera minuscule. De plus, les NSArrays présentent d'autres avantages de vitesse par rapport aux NSSets. Comme toujours, c'est un compromis.
FreeAsInBeer
5
NSArray *Arr;
NSSet *Nset;

Arr=[NSArray arrayWithObjects:@"1",@"2",@"3",@"4",@"2",@"1", nil];
Nset=[NSSet setWithObjects:@"1",@"2",@"3",@"3",@"5",@"5", nil];

NSLog(@"%@",Arr);
NSLog(@"%@",Nset);

le tableau

04/12/2015 11: 05: 40.935 [598: 15730] (1, 2, 3, 4, 2, 1)

l'ensemble

04/12/2015 11: 05: 43.362 [598: 15730] {(3, 1, 2, 5)}

abc221
la source
4

Les principales différences ont déjà été données dans d'autres réponses.

Je voudrais juste noter qu'en raison de la façon dont les ensembles et les dictionnaires sont implémentés (c'est-à-dire en utilisant des hachages), il faut faire attention à ne pas utiliser d'objets mutables pour les clés.

Si une clé est mutée, le hachage changera (probablement) aussi, pointant vers un autre index / compartiment dans la table de hachage. La valeur d'origine ne sera pas supprimée et sera effectivement prise en compte lors de l'énumération ou de la demande à la structure de sa taille / nombre.

Cela peut conduire à des bogues très difficiles à localiser.

Joakim
la source
3

Ici vous trouverez une comparaison assez approfondie des NSArrayet NSSetdatastructures.

Conclusions brèves:

Oui, NSArray est plus rapide que NSSet pour simplement tenir et itérer. Aussi peu que 50% plus rapide pour la construction et jusqu'à 500% plus rapide pour l'itération. Leçon: si vous avez seulement besoin d'itérer le contenu, n'utilisez pas de NSSet.

Bien sûr, si vous devez tester l'inclusion, travaillez dur pour éviter NSArray. Même si vous avez besoin à la fois de tests d'itération et d'inclusion, vous devriez probablement toujours choisir un NSSet. Si vous avez besoin de garder votre collection ordonnée et de tester également l'inclusion, vous devriez envisager de conserver deux collections (un NSArray et un NSSet), chacune contenant les mêmes objets.

NSDictionary est plus lent à construire que NSMapTable - car il doit copier les données clés. Cela compense cela en étant plus rapide à rechercher. Bien sûr, les deux ont des capacités différentes, donc la plupart du temps, cette détermination doit être faite sur d'autres facteurs.

Che
la source
Bien que cela puisse théoriquement répondre à la question, il serait préférable d'inclure ici les parties essentielles de la réponse et de fournir le lien pour référence.
Tunaki
2

Vous utiliserez généralement un ensemble lorsque la vitesse d'accès est essentielle et que l'ordre n'a pas d'importance , ou est déterminé par d'autres moyens (via un prédicat ou un descripteur de tri). Core Data, par exemple, utilise des ensembles lorsque des objets gérés sont accessibles via une relation à plusieurs

iDevAmit
la source
1

Juste pour en ajouter un peu, j'utilise parfois set juste pour supprimer les doublons du tableau comme: -

NSMutableSet *set=[[NSMutableSet alloc]initWithArray:duplicateValueArray]; // will remove all the duplicate values
essayezKuldeepTanwar
la source