Wann ist es besser, ein NSSet über ein NSArray zu verwenden?

112

Ich habe NSSets oft in meinen Apps verwendet, aber selbst noch nie eines erstellt.

Wann ist es besser, ein NSSetim Gegensatz zu einem zu verwenden NSArrayund warum?

geminiCoder
quelle

Antworten:

173

Wenn die Reihenfolge der Elemente in der Sammlung nicht wichtig ist, bieten Sets eine bessere Leistung beim Auffinden von Elementen in der Sammlung.

Der Grund dafür ist, dass eine Gruppe Hash-Werte verwendet, um Elemente (wie ein Wörterbuch) zu finden, während ein Array seinen gesamten Inhalt durchlaufen muss, um ein bestimmtes Objekt zu finden.

Ole Begemann
quelle
9
log (1) vs log (n)
Rohan-Patel
25
@ rohan-patel Richtig ist O (1) gegen O (n)
Mansurov Ruslan
1
Wenn bestellt: O (1) vs O (logn), da die binäre Suche anwendbar ist. Wenn ungeordnet, dann O (1) vs O (n)
baskInEminence
180

Das Bild aus Apples Dokumentation beschreibt es sehr gut:

Objective-C-Sammlungen

Arrayist eine geordnete Folge von Elementen (die Reihenfolge wird beim Hinzufügen beibehalten)

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

Setist eine eindeutige (keine Duplikate), ungeordnete Liste von Elementen

[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
quelle
2
In Ihrem Beispiel fügen Sie einem Array und einer Menge Grundelemente hinzu. Beides ist nicht möglich, da sie nur Objekte enthalten können.
FreeAsInBeer
10
Vielen Dank für Ihre Bearbeitung @Zaheer, aber es war tatsächlich ungültig. Ich habe keine Grundelemente hinzugefügt. Ich habe Literale hinzugefügt.
James Webster
Tolle Erklärung :) +1 :)
Karun
1
Liebe deine Erklärung! +1 dafür
Rebellion
66

Die beste Antwort darauf ist Apples eigene Dokumentation .

Geben Sie hier die Bildbeschreibung ein

Der Hauptunterschied besteht darin, dass NSArrayes sich um eine bestellte Sammlung und NSSetum eine ungeordnete Sammlung handelt.

Es gibt mehrere Artikel, die über den Geschwindigkeitsunterschied zwischen den beiden sprechen, wie diesen hier . Wenn Sie eine ungeordnete Sammlung durchlaufen, NSSetist das großartig. In vielen Fällen müssen Sie jedoch Dinge tun, die nur ein NSArrayMensch tun kann, sodass Sie die Geschwindigkeit für diese Fähigkeiten opfern.

NSSet

  • Greifen Sie hauptsächlich durch Vergleich auf Elemente zu
  • Ungeordnet
  • Erlaubt keine Duplikate

NSArray

  • Kann über den Index auf Elemente zugreifen
  • Bestellt
  • Ermöglicht Duplikate

Das ist alles, was es wirklich zu tun gibt! Lassen Sie mich wissen, ob das hilft.

woz
quelle
Sie müssen nicht immer NSSetfür die Indizierung opfern . Es ist üblich, zwei verschiedene Datenstrukturen für dieselben Daten zu verwenden. Oder Sie erstellen und indizieren dieses Array :) Aber dann ist es besser, eine Datenbank zu verwenden, in der es bereits implementiert ist.
Sulthan
"Erstellen Sie einen Index für dieses Array". Sie können keinen Index für ein NSSet erstellen. Es gibt viele verschiedene Techniken, die Sie verwenden können. Und wenn Sie sowohl im Speicher als auch in der Verarbeitungsleistung Opfer bringen müssen, dann machen Sie es falsch.
Sulthan
Da es sich bei der Frage um NSSetund handelt NSArray, ist meine Antwort korrekt und vollständig. Ja, Sie können andere Datenstrukturen erstellen, aber ich vergleiche nur diese beiden.
Woz
Ich habe zugestimmt, aber Ihre Antwort ist falsch, wenn Sie über Opfer sprechen. Wenn Sie einige Funktionen von NSArrayund einige Funktionen von benötigen, lautet NSSetdie richtige Antwort nicht "Leistung nutzen NSArrayund opfern". Die Antwort ist, beide zu kombinieren oder eine andere Datenstruktur zu verwenden.
Sulthan
Ich hätte gesagt, dass der Hauptunterschied für eindeutige Objekte besteht, bei denen ein Array Duplikate haben kann. Der Ordnungsaspekt ist dieser Tatsache untergeordnet.
Malhal
12

NSOrderedSet ist in iOS 5+ verfügbar, sodass der Hauptunterschied darin besteht, ob Sie doppelte Objekte in der Datenstruktur möchten.

Jason
quelle
9

NSArray :

  1. Geordnete Datenerfassung
  2. Ermöglicht Duplikate
  3. Es ist ein Objekt vom Typ Sammlung

NSSet :

  1. Ungeordnete Datenerfassung
  2. Erlaubt keine Duplikate
  3. Es ist auch ein Objekt vom Typ Sammlung
iOS Lifee
quelle
7

Ein Array wird verwendet, um über ihren Index auf Elemente zuzugreifen. Jedes Element kann mehrmals in das Array eingefügt werden. Arrays behalten die Reihenfolge ihrer Elemente bei.

Ein Set wird grundsätzlich nur verwendet, um zu überprüfen, ob sich der Artikel in der Sammlung befindet oder nicht. Die Artikel haben kein Konzept der Reihenfolge oder Indizierung. Sie können einen Gegenstand nicht zweimal in einem Satz haben.

Wenn ein Array überprüfen möchte, ob es ein Element enthält, muss es alle seine Elemente überprüfen. Sets sind so konzipiert, dass sie schnellere Algorithmen verwenden.

Sie können sich eine Menge wie ein Wörterbuch ohne Werte vorstellen.

Beachten Sie, dass Array und Set nicht die einzigen Datenstrukturen sind. Es gibt andere, z. B. Warteschlange, Stapel, Haufen, Fibonaccis Haufen. Ich würde empfehlen, ein Buch über Algorithmen und Datenstrukturen zu lesen.

Weitere Informationen finden Sie in Wikipedia .

Sulthan
quelle
Tatsächlich muss ein Array nur bis zu dem Punkt überprüft werden, an dem das Element gefunden wird. Wenn sich das Element im Array befindet, muss sehr selten jedes Element überprüft werden.
FreeAsInBeer
Ja, wie Sie sagen "Wenn sich das Element im Array befindet". Wenn Sie dies erwarten, müssen Sie nicht überprüfen, ob es vorhanden ist oder nicht. Die Komplexität der containsOperation ist O(n). Anzahl der Vergleiche, wenn nicht im Array n. Die durchschnittliche Anzahl von Vergleichen, wenn sich das Objekt im Array befindet, beträgt n/2. Selbst wenn das Objekt gefunden wird, ist die Leistung schrecklich.
Sulthan
Leistung wäre nur mit einem großen Array schrecklich. Wenn Sie wissen, dass das Array ziemlich groß werden kann, gibt es Möglichkeiten, die Leistung des Arrays zu verbessern, z. B. die Verwendung eines Arrays von Arrays.
FreeAsInBeer
Wenn die Gleichheitsoperation teuer ist, sehen Sie den Unterschied auch bei Arrays mit 3 Elementen. Und das gleiche Verhalten wie bei einem großen Array kann auftreten, wenn Sie die Operation häufig wiederholen (z. B. die Operation in einem 'for'-Zyklus verwenden). Haben Sie von amortisierter Komplexität gehört? Die Komplexität ist immer noch linear und die Leistung ist im Vergleich zu einem Satz schrecklich (normalerweise mit konstanter Komplexität).
Sulthan
Offensichtlich wird es einen Unterschied geben, ich sage nur, dass die große Notation exponentiell ist; Bei kleinen Arrays ist der Unterschied winzig. Auch NSArrays haben andere Geschwindigkeitsvorteile gegenüber NSSets. Wie immer ist es ein Kompromiss.
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);

das Array

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

der Satz

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

abc221
quelle
4

Die Hauptunterschiede wurden bereits in anderen Antworten angegeben.

Ich möchte nur darauf hinweisen, dass aufgrund der Art und Weise, wie Mengen und Wörterbücher implementiert werden (dh Hashes verwenden), darauf geachtet werden sollte, keine veränderlichen Objekte für die Schlüssel zu verwenden.

Wenn ein Schlüssel mutiert ist, ändert sich (wahrscheinlich) auch der Hash und zeigt auf einen anderen Index / Bucket in der Hash-Tabelle. Der ursprüngliche Wert wird nicht gelöscht und tatsächlich berücksichtigt, wenn die Struktur aufgelistet oder nach ihrer Größe / Anzahl gefragt wird.

Dies kann zu einigen wirklich schwer zu lokalisierenden Fehlern führen.

Joakim
quelle
3

Hier finden Sie einen ziemlich gründlichen Vergleich der NSArrayund der NSSetDatenstrukturen.

Kurze Schlussfolgerungen:

Ja, NSArray ist schneller als NSSet, da es einfach gehalten und iteriert werden kann. Nur 50% schneller zum Erstellen und bis zu 500% schneller zum Iterieren. Lektion: Wenn Sie nur Inhalte iterieren müssen, verwenden Sie kein NSSet.

Wenn Sie auf Inklusion testen müssen, arbeiten Sie natürlich hart, um NSArray zu vermeiden. Selbst wenn Sie sowohl Iterations- als auch Inklusionstests benötigen, sollten Sie wahrscheinlich immer noch ein NSSet auswählen. Wenn Sie Ihre Sammlung geordnet halten und auch auf Aufnahme prüfen müssen, sollten Sie zwei Sammlungen (eine NSArray- und eine NSSet-Sammlung) behalten, die jeweils dieselben Objekte enthalten.

NSDictionary ist langsamer zu erstellen als NSMapTable, da die Schlüsseldaten kopiert werden müssen. Dies wird durch eine schnellere Suche ausgeglichen. Natürlich haben die beiden unterschiedliche Fähigkeiten, so dass diese Bestimmung die meiste Zeit auf anderen Faktoren beruhen sollte.

Che
quelle
Während dies theoretisch die Frage beantworten kann, wäre es vorzuziehen , die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen.
Tunaki
2

Normalerweise verwenden Sie ein Set, wenn die Zugriffsgeschwindigkeit von entscheidender Bedeutung ist und die Reihenfolge keine Rolle spielt oder auf andere Weise (durch ein Prädikat oder einen Sortierdeskriptor) bestimmt wird. Core Data verwendet beispielsweise Mengen, wenn auf verwaltete Objekte über eine To-Many-Beziehung zugegriffen wird

iDevAmit
quelle
1

Nur um ein bisschen davon hinzuzufügen, benutze ich set manchmal nur, um Duplikate aus dem Array zu entfernen, wie: -

NSMutableSet *set=[[NSMutableSet alloc]initWithArray:duplicateValueArray]; // will remove all the duplicate values
tryKuldeepTanwar
quelle