NSArrayではなくNSSetを使用するほうが良い場合はいつですか?


112

私はアプリでNSSetsを何度も使用しましたが、自分でNSSetsを作成したことはありません。

それが使用することをお勧めする場合であるNSSetとは対照的に、NSArrayその理由は?

回答:


173

コレクション内のアイテムの順序が重要ではない場合、セットを使用すると、コレクション内のアイテムを検索する際のパフォーマンスが向上します。

その理由は、セットはハッシュ値を使用してアイテム(辞書など)を見つけるのに対し、配列は特定のオブジェクトを見つけるためにコンテンツ全体を反復処理する必要があるためです。


9
log(1)対log(n)
rohan-patel 2014年

25
@ rohan-patel正解はO(1)対O(n)
Mansurov Ruslan

1
注文した場合:O(1)対O(logn)は、バイナリ検索が適用されるためです。順序付けされていない場合、O(1)対O(n)
baskInEminence

180

Appleのドキュメンテーションからの画像はそれを非常によく説明しています:

Objective-Cコレクション

Arrayされて注文した要素のシーケンスを(あなたが追加したときに順序が維持されています)

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

Setされていない異なる(非重複)、順序付けられていない要素のリスト

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

2
あなたの例では、配列とセットにプリミティブを追加しています。オブジェクトのみを含むことができるため、どちらも不可能です。
FreeAsInBeer

10
@Zaheerの編集に感謝しますが、実際には無効でした。プリミティブを追加していませんでした。リテラルを追加していました。
James Webster

素晴らしい説明:) +1 :)
Karun

1
あなたの説明が大好きです!そのための+1
反乱

66

これに対する最良の答えは、Apple自身のドキュメントです。

ここに画像の説明を入力してください

主な違いはNSArray、順序付けられたコレクションとNSSet順序付けられていないコレクションです。

この1つのように、2つの速度の違いについて述べた記事がいくつかあります。順序付けられていないコレクションを繰り返し処理する場合NSSetは、すばらしいです。ただし、多くの場合、あなただけがNSArrayできることをする必要があるので、それらの能力の速度を犠牲にします。

NSSet

  • 主に比較によってアイテムにアクセスする
  • 順不同
  • 重複を許可しない

NSArray

  • インデックスでアイテムにアクセスできます
  • 順序付けられました
  • 重複を許可

これですべてです。問題が解決したかどうかをお知らせください。


NSSetインデックス作成のために常に犠牲にする必要はありません。同じデータに対して2つの異なるデータ構造を使用するのが一般的です。または、その配列にビルドしてインデックスを付けます。
スルタン

「その配列にインデックスを作成する」。NSSetにインデックスを作成することはできません。使用できるテクニックはたくさんあります。そして、メモリと処理能力の両方を犠牲にする必要がある場合、それは間違っています。
スルタン

質問は約あるのでNSSetそしてNSArray、私の答えは正確かつ完全です。はい、他のデータ構造を構築できますが、私はこれら2つを比較しているだけです。
ウォズ

私は賛成票を投じましたが、犠牲について話すとき、あなたの答えは正しくありません。の機能NSArrayとの機能が必要な場合NSSet、正解は「NSArrayパフォーマンスの使用と犠牲」ではありません。答えは、両方を組み合わせるか、異なるデータ構造を使用することです。
スルタン

主な違いは、配列が重複する可能性がある一意のオブジェクトが設定されることです。順序の側面は、その事実に次ぐものです。
Malhal

12

NSOrderedSetはiOS 5以降で使用できるため、主な違いは、データ構造でオブジェクトを複製するかどうかです。


9

NSArray

  1. 順序付けられたデータの収集
  2. 重複を許可
  3. コレクション型オブジェクトです

NSSet

  1. 順不同のデータ収集
  2. 重複を許可しない
  3. コレクション型オブジェクトでもあります

7

配列は、インデックスによってアイテムにアクセスするために使用されます。任意のアイテムを配列に複数回挿入できます。配列は要素の順序を管理します。

セットは基本的に、アイテムがコレクション内にあるかどうかを確認するためだけに使用されます。アイテムには、順序やインデックスの概念はありません。セット内のアイテムを2回持つことはできません。

配列に要素が含まれているかどうかを確認する場合は、そのすべての項目を確認する必要があります。セットは、より高速なアルゴリズムを使用するように設計されています。

値のない辞書のようなセットを想像できます。

配列とセットだけがデータ構造ではないことに注意してください。キュー、スタック、ヒープ、フィボナッチのヒープなど、他にもあります。アルゴリズムとデータ構造についての本を読むことをお勧めします。

詳細については、ウィキペディアを参照してください。


実際、配列は、アイテムが見つかるまでチェックするだけで済みます。アイテムが配列内にある場合、すべてのアイテムをチェックする必要はほとんどありません。
FreeAsInBeer

はい、「アイテムが配列にある場合」と言います。これが予想される場合、それが存在するかどうかを確認する必要はありません。contains操作の複雑さはO(n)です。配列にない場合の比較数はnです。オブジェクトが配列内にある場合の比較の平均数はn/2です。オブジェクトが見つかったとしても、パフォーマンスはひどいです。
スルタン

大規模なアレイではパフォーマンスはひどいものになります。配列が非常に大きくなる可能性があることがわかっている場合は、配列の配列を使用するなど、配列のパフォーマンスを向上させる方法があります。
FreeAsInBeer

等価演算に負荷がかかる場合は、3項目の配列でも違いがわかります。また、操作を何度も繰り返すと、大きな配列と同じ動作が発生する可能性があります(たとえば、「for」サイクルで操作を使用します)。償却済みの複雑さについて聞いたことがありますか?複雑さは依然として線形であり、パフォーマンスはセット(通常は一定の複雑さ)と比較してひどいです。
スルタン

明らかに違いがあります。私は、ビッグオー表記法が指数関数的であることを述べています。小さな配列では、違いはごくわずかです。また、NSArraysにはsに比べて他の速度上の利点がありNSSetます。いつものように、それはトレードオフです。
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);

配列

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

セット

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


4

主な違いはすでに他の回答で示されています。

セットとディクショナリの実装方法(つまり、ハッシュを使用する)のため、キーに可変オブジェクトを使用しないように注意する必要があります。

キーが変更されると、ハッシュも(おそらく)変更され、ハッシュテーブル内の別のインデックス/バケットをポイントします。元の値は削除されず、構造のサイズや数を列挙または要求するときに実際に考慮されます。

これにより、バグの特定が非常に困難になる可能性があります。


3

ここでは、NSArrayNSSetデータ構造のかなり完全な比較を見つけることができます。

短い結論:

はい、NSArrayはNSSetよりも高速に保持および反復できます。構築は50%程度速く、反復は500%程度速くなります。レッスン:コンテンツを反復するだけの場合は、NSSetを使用しないでください。

もちろん、包含をテストする必要がある場合は、NSArrayを回避するために一生懸命に作業してください。反復テストと包含テストの両方が必要な場合でも、おそらくNSSetを選択する必要があります。コレクションの順序を維持し、包含をテストする必要がある場合は、2つのコレクション(NSArrayとNSSet)を保持することを検討してください。それぞれに同じオブジェクトが含まれています。

NSDictionaryはNSMapTableよりも構築に時間がかかります—キーデータをコピーする必要があるためです。ルックアップが高速になることで、これを補います。もちろん、2つは異なる機能を備えているため、ほとんどの場合、この決定は他の要因で行う必要があります。


これにより理論的には質問に答えることができますが、ここに答えの本質的な部分を含め、参照用のリンクを提供することが望ましいでしょう
Tunaki、2016

2

通常、Setは、アクセス速度が重要であり順序が重要ない場合、または他の方法で(述語またはソート記述子を使用して)決定される場合に使用します。たとえばコアデータは、多対多の関係を介して管理対象オブジェクトにアクセスするときにセットを使用します


1

少しだけ追加するために、配列の重複を削除するために時々setを使用します:-

NSMutableSet *set=[[NSMutableSet alloc]initWithArray:duplicateValueArray]; // will remove all the duplicate values
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.