web-dev-qa-db-ja.com

値に一致する値をNSArrayで検索

NSArrayにobjectsがあり、name(NSString型)という特定のプロパティがあります。
NSStringの2番目のNSArrayはnamesです。

すべてのobjectsのNSArrayを取得したいのですが、その.nameプロパティは、2番目のNSArrayのnamesのいずれかに一致します。

これは非常に頻繁に必要とされるため、どのようにすれば、迅速かつ効率的にこれを行うことができますか。

22
Jonathan.

現在のデータ構造では、2番目の配列の各メンバーに対して最初の配列を1回ループすることにより、O(n ^ 2)時間内でしか実行できません。

NSMutableArray * array = [NSMutableArray array];
for (NSString * name in names) {
    for (MyObject * object in objects) {
        if ([[myObject name] isEqualToString:name]) {
            [array addObject:object];
        }
    }
}

(Stefanが提案する代替案:オブジェクト配列をループ処理し、各オブジェクトの名前がcontainsObject:かどうかを名前配列に尋ねます。)

しかし、これを本当に高速にする必要がある場合(実際に実行する頻度と同じくらいに配列のサイズに依存します)、最初の配列のnamesをそれらにマッピングするNSDictionaryを導入することでこれを改善できますオブジェクト。その後、これらの各ルックアップはO(1)であり、全体の時間はO(n)です(この辞書は常にオブジェクトの配列と同期している必要があります。合理的なアクセサーでは困難です。この手法には、同じnameが複数のオブジェクトに現れないという制約もあります。

この結果を取得する別の方法(および最後の制約を持たない)は、2番目のコレクションにNSSetを使用し、名前のセットのそれぞれでcontainsObject:を呼び出すオブジェクト配列を調べます。この手法が優れているかどうかは、2つのコレクションがほぼ同じサイズであるか、一方が他方よりもはるかに大きいかどうかによって決まります。

14
Ben Zotto

なぜあなたのためにそれをするために述語を使うだけではありませんか?:

// For number kind of values:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF = %@", value];
NSArray *results = [array_to_search filteredArrayUsingPredicate:predicate];

// For string kind of values:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", value];
NSArray *results = [array_to_search filteredArrayUsingPredicate:predicate];

// For any object kind of value (yes, you can search objects also):
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", value];
NSArray *results = [array_to_search filteredArrayUsingPredicate:predicate];
72
Lukasz

簡単な方法を次に示します。

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", nameToFind];
[listOfItems filteredArrayUsingPredicate:predicate];
14
Stephen Poletto

私はこの方法を使用したい:

NSIndexSet *indexes = [_items indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
   return ((MyObject *)obj).name isEqualToString:name];
}];

if (indexes.count != 0) {
//extract your objects from the indexSet, and do what you like...
}
6
Lirik
NSMutableArray * foundNames = [NSMutableArray array];
for (MyObject * objectWithName in objectCollection) {
    if ([names containsObject:objectWithName.name]) {
        [foundNames objectWithName];
    }
}
2
Stefan H

最も役立つ方法は次のとおりです。

filteredArrayUsingPredicate:

そして

indexesOfObjectsPassingTest:

2つ目はコードブロックを使用しますが、4.0より前のiOSでは使用できません

これらは両方とも、直接反復するよりも効率的です。

ここに良い例があります: http://developer.Apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxUsing.html

2
NWCoder
NSMutableArray* solutions = [NSMutableArray array];

for (Object* object in objects){
   for (NSString* name in names){
       if ([object.name isEqualToString:name]){
          [solutions addObject:object];
          break; // If this doesnt work remove this
       }
   }
}
0
Justin Meiners
int count=0;

if (range.location!=NSNotFound)
  {                   
  [searchindex addObject:[NSString stringWithFormat:@"%d",count]];           
  }
0
kabeer