J'ai un NSArray de objects
, qui a une propriété particulière appelée name
(type NSString).
J'ai un deuxième NSArray de NSStrings qui sont names
.
Je voudrais obtenir un NSArray de tous les objects
dont .name
la propriété correspond à l'un des names
dans le deuxième NSArray.
Comment dois-je procéder, rapidement et efficacement, car cela sera nécessaire assez souvent.
Avec vos structures de données actuelles, vous ne pouvez le faire qu'en temps O (n ^ 2) en bouclant le premier tableau une fois pour chaque membre du second tableau:
NSMutableArray * array = [NSMutableArray array];
for (NSString * name in names) {
for (MyObject * object in objects) {
if ([[myObject name] isEqualToString:name]) {
[array addObject:object];
}
}
}
(Alterner comme suggéré par Stefan: faire une boucle sur le tableau des objets et demander au tableau des noms s'il containsObject:
pour le nom de chaque objet.)
Mais si cela doit vraiment être plus rapide (cela dépend vraiment de la taille des tableaux autant que de la fréquence à laquelle vous le faites), vous pouvez améliorer cela en introduisant un NSDictionary qui mappe le names
du premier tableau à leur objets. Ensuite, chacune de ces recherches est O(1) et le temps global est O (n). (Vous devez garder ce dictionnaire toujours synchronisé avec le tableau des objets, qui n'est pas ' t difficile avec des accesseurs raisonnables. Cette technique a aussi la contrainte que le même name
ne peut pas apparaître sur plus d'un objet.)
Une autre façon d'obtenir ce résultat (et qui n'a pas cette dernière contrainte) est d'utiliser un NSSet pour votre deuxième collection, puis de parcourir le tableau d'objets appelant containsObject:
avec chacun sur l'ensemble des noms. Que cette technique soit meilleure dépend du fait que vos deux collections sont à peu près de la même taille ou si l'une est beaucoup plus grande que l'autre.
Pourquoi ne pas simplement utiliser des prédicats pour le faire pour vous?:
// 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];
Voici un moyen simple:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@", nameToFind];
[listOfItems filteredArrayUsingPredicate:predicate];
J'aime utiliser cette méthode:
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...
}
NSMutableArray * foundNames = [NSMutableArray array];
for (MyObject * objectWithName in objectCollection) {
if ([names containsObject:objectWithName.name]) {
[foundNames objectWithName];
}
}
Les méthodes les plus utiles seront:
filteredArrayUsingPredicate:
et
indexesOfObjectsPassingTest:
Le second utilise un bloc de code, non disponible sur iOS avant 4.0
Ces deux éléments seront plus efficaces que l'itération directe.
Il y a un bon exemple ici: http://developer.Apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxUsing.html
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
}
}
}
int count=0;
if (range.location!=NSNotFound)
{
[searchindex addObject:[NSString stringWithFormat:@"%d",count]];
}