NSSetからオブジェクトを取得する


回答:


139

セットにはいくつかの使用例があります。を介して列挙(例:enumerateObjectsUsingBlockまたはNSFastEnumeration)、containsObjectメンバーシップのテストを呼び出すanyObject、メンバーを取得する(ランダムではない)、またはを使用して配列に変換する(順不同)allObjects

セットは、重複を避け、順序を気にせず、迅速なメンバーシップテストが必要な場合に適しています。


7
また、セットにmember:メッセージを送信して、重複の可能性がある既知のオブジェクトを検索することもできます。が返されたnil場合、セットには渡したオブジェクトと同じオブジェクトが含まれていません。オブジェクトポインタを返す場合、返されるポインタは既にセットにあるオブジェクトを指します。セット内のオブジェクトは実装する必要がhashありisEqual:、これが役立つために必要です。
Peter Hosey、2010

@PeterHosey 実装hash する必要はないと思います。あなたがそれをしたなら、それはただずっと速く行くでしょう。
fumoboy007 2013

2
@ fumoboy007:セットに保存したり、ディクショナリのキーとして使用したりできます。hashNSObjectプロトコルのドキュメントから:「2つのオブジェクトが(isEqual:メソッドによって決定されるように)等しい場合、それらは同じハッシュ値を持つ必要があります。」現在、NSObjectの実装はオブジェクトのID(アドレス)hashisEqual:使用しています。をオーバーライドする場合isEqual:、同一ではないが等しいオブジェクトの可能性を設定しhashます。オーバーライドもしない場合でも、ハッシュは異なります。これは、等しいオブジェクトのハッシュが等しいという要件に違反しています。
Peter Hosey 2013

1
@ fumoboy007:ハッシュテーブルがどのように機能するかを検討します。コンテナにはいくつかのバケットの配列があり、各受信オブジェクトのハッシュを使用して、そのオブジェクトをどのバケットに入れるかを決定します。などのルックアップのmember:場合、コンテナはその1つだけを調べますバケット(これは、セットがメンバーシップテストで配列よりもはるかに高速であり、辞書がキー値ルックアップで並列配列よりもはるかに高速である理由です)。探しているオブジェクトのハッシュが間違っていると、コンテナは間違ったバケットを調べ、一致するものを見つけられません。
Peter Hosey 2013

@PeterHoseyおっと…のデフォルトの実装-[NSObject hash]が0 であると誤って思いました。= S
fumoboy007 2013

31

NSSetにはメソッドobjectAtIndexがありません:

すべてのオブジェクトのNSArrayを返すallObjectsを呼び出してみてください。


返された配列が順序付けられているかどうかはわかりますか?つまり、「setByAddingObject」を使用してオブジェクトをセットに追加し、「allObjects」を使用した場合、どうなりますか?配列の要素は、オブジェクトを追加した順序で並べられていますか?
iosMentalist 2012

結果の配列をNSSortPredicateでソートするだけで問題ありません
Jason

特定の1つのオブジェクトのみに関心がある場合は、filteredSetUsingPredicateアプローチを使用することをお勧めします。
akw 2013年

17

必要なオブジェクトを選択するための何らかの一意の識別子がある場合は、filteredSetUsingPredicateを使用できます。

最初に述語を作成します(オブジェクト内の一意のIDが「識別子」と呼ばれ、それがNSStringであると仮定します):

NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];

次に、述語を使用してオブジェクトを選択します。

NSObject *myChosenObject = [mySet filteredSetUsingPredicate:myPredicate].anyObject;

13

NSArray *myArray = [myNSSet allObjects];

MyObject *object = [myArray objectAtIndex:(NSUInteger *)]

NSUIntegerを目的のオブジェクトのインデックスに置き換えます。


1
MyObject * object = [myArray objectAtIndex:(NSUInteger *)]
John D.

8

Swift3およびiOS10の場合:

//your current set
let mySet : NSSet
//targetted index
let index : Int
//get object in set at index
let object = mySet.allObjects[index]

6

NSSetは、メソッドisEqual:を使用して(そのセットに入れたオブジェクトは、さらにハッシュメソッドをオーバーライドする必要があります)、オブジェクトがその中にあるかどうかを判断します。

したがって、たとえば、一意性をid値で定義するデータモデルがある場合(プロパティは次のようになります。

@property NSUInteger objectID;

次に、isEqual:asを実装します

- (BOOL)isEqual:(id)object
{
  return (self.objectID == [object objectID]);
}

そしてあなたはハッシュを実装することができます:

- (NSUInteger)hash
{
 return self.objectID;  // to be honest, I just do what Apple tells me to here
                       // because I've forgotten how Sets are implemented under the hood
}

次に、そのIDを持つオブジェクトを取得できます(NSSetにあるかどうかも確認できます)。

MyObject *testObject = [[MyObject alloc] init];
testObject.objectID = 5; // for example.  

// I presume your object has more properties which you don't need to set here 
// because it's objectID that defines uniqueness (see isEqual: above)

MyObject *existingObject = [mySet member: testObject];

// now you've either got it or existingObject is nil

しかし、ええ、NSSetから何かを取得する唯一の方法は、そもそもその一意性を定義する方法を検討することです。

何が速いかはテストしていませんが、列挙は使用しないようにします。これは線形の可能性があるためです。member:メソッドを使用すると、はるかに高速になります。これが、NSArrayではなくNSSetを使用する理由の1つです。



0

ほとんどの場合、特定のオブジェクトをセットから取得する必要はありません。セットにオブジェクトが含まれているかどうかを確認するためのテストに関心があります。それがセットが良いことです。オブジェクトがコレクション内にあるかどうかを確認する場合、セットは配列よりもはるかに高速です。

取得するオブジェクトが気にならない場合-anyObjectは、バッグに手を入れて何かをつかむなど、セットから1つのオブジェクトを取得するだけを使用します。

Dog *aDog = [dogs anyObject]; // dogs is an NSSet of Dog objects

取得-memberするオブジェクトに関心がある場合は、それを使用してオブジェクトを戻すか、セットにない場合はnilを使用します。呼び出す前に、オブジェクトを既に持っている必要があります。

Dog *spot = [Dog dogWithName:@"Spot"];
// ...
Dog *aDog = [dogs member:spot]; // Returns the same object as above

Xcodeで実行して詳細を理解できるコードをいくつか示します

NSString *one = @"One";
NSString *two = @"Two";
NSString *three = @"Three";

NSSet *set = [NSSet setWithObjects:one, two, three, nil];

// Can't use Objective-C literals to create a set.
// Incompatible pointer types initializing 'NSSet *' with an expression of type 'NSArray *'
//  NSSet *set = @[one, two, three];

NSLog(@"Set: %@", set);
// Prints looking just like an array but is actually not in any order
//Set: {(
//     One,
//     Two,
//     Three
//     )}

// Get a random object
NSString *random = [set anyObject];
NSLog(@"Random: %@", random); // Random: One

// Iterate through objects. Again, although it prints in order, the order is a lie
for (NSString *aString in set) {
    NSLog(@"A String: %@", aString);
}

// Get an array from the set
NSArray *array = [set allObjects];
NSLog(@"Array: %@", array);

// Check for an object
if ([set containsObject:two]) {
    NSLog(@"Set contains two");
}

// Check whether a set contains an object and return that object if it does (nil if not)
NSString *aTwo = [set member:two];
if (aTwo) {
    NSLog(@"Set contains: %@", aTwo);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.