Filtrage d'un grand NSArray avec NSPredicate

J'ai un tableau contenant 170k strings (mots dans un dictionary), et une string, ressemblant à quelque chose comme "glapplega". J'essaie d'extraire le mot "apple" de la string (avec "apple" étant un mot dans le tableau). Je dois également m'assurer que le mot extrait est au less 3 caractères. Le code que j'ai en ce moment est le suivant:

NSPredicate *wordPredicate = [NSPredicate predicateWithFormat:@"'%@' contains[cd] SELF", ssortingng]; NSPredicate *lengthPredicate = [NSPredicate predicateWithFormat:@"SELF.length > 2"]; NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[wordPredicate, lengthPredicate]]; return [_words filteredArrayUsingPredicate:lengthPredicate]; 

Le prédicat de longueur fonctionne de lui-même, mais le mot prédicat ne le fait pas (il returnne un tableau vide, bien que "apple" soit un mot dans le tableau).

Je soupçonne qu'il pourrait y avoir un problème avec l'utilisation de SELF comme expression correcte dans le prédicat, comme tous les exemples que j'ai trouvés l'ont comme l'expression de gauche, bien que je n'ai aucun moyen de le confirmer.

Edit : Je suis conscient que cela peut probablement être accompli avec regexs (comme décrit ici ), mais j'espérais qu'il y aurait un moyen de contourner cela, car les regex peuvent être lents avec un set de données aussi important.

Il est facile de résoudre ce problème si vous le faites vous-même en utilisant un prédicat de bloc. À un certain point, un NSPredicate formaté devrait se résumer à ceci, donc il ne devrait pas y avoir beaucoup de coup de performance. -[NSSsortingng rangeOfSsortingng:] peut être utilisé pour tester l'inclusion de la string.

 return [_words filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL (id evaluatedSsortingng, NSDictionary *bindings) { return ssortingng.length > 2 && [ssortingng rangeOfSsortingng:evaluatedSsortingng].location != NSNotFound; }]]; 

Vous savez ce que votre hypothèse et prédicat ci-dessus est parfaitement valide. La seule chose que vous avez fait de mal est des citations. Reformate ton prédicat et fais comme ça,

  NSArray * array = @[@"Apple", @"lega", @"foo", @"bar"]; NSSsortingng *ssortingng = @"glapplega"; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%@ contains[cd] SELF and SELF.length > 2", ssortingng]; NSLog(@"%@",[array filteredArrayUsingPredicate:predicate]); ( Apple, lega ) 

Lorsque vous spécifiez le format et fournissez la string au format, le prédicat place les guillemets par lui-même. Donc, vous avez été confondu ici.

 #define rchar (rand() % ('z'-'a') + 'a') - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { NSMutableArray * mar = [NSMutableArray new]; for (int i = 0; i<170000; i++) { NSSsortingng * str = [NSSsortingng ssortingngWithFormat:@"%c%c%c%c",rchar, rchar, rchar, rchar]; [mar addObject:str]; } NSSsortingng * bigStr = @"asdfghjkl;loiuytrdcvcdrtgvfrtghvcftyghvfghcfdtyjghvncdfjtygmvcnfhjghjkgfhdgsxgrecrvtbkunhlmnhubkujvytchrtxgrecdjvbyhnkbjgcfhvyjhbghnkbjchgdfvbghnukbytvjycterwxrzewxcevfbjnkmjohgytreytwexkutckhtdtcfhvjgkjmhgcjhewwzsserdp9dlkuydssqwsxdchvggjhmgbj"; NSDate *start = [NSDate date]; NSArray * marFiltered = [mar filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { return [bigStr rangeOfSsortingng:evaluatedObject].length>2; }]]; NSLog(@"found %lu items in %f seconds", (unsigned long)[marFiltered count], -[start timeIntervalSinceNow]); } 

sortie:

 2014-05-11 09:09:53.048 170k[89396:303] found 85 items in 0.542431 seconds 

Vous pouvez essayer deux options pour définir le prédicat. Une string de format et un bloc. Voici un peu de code qui démontre les deux. J'ai joué un peu avec les deux et je peux partager que la performance est la même. J'ai seulement eu la patience de l'exécuter avec une valeur maximale de INT32_MAX / 2 (beaucoup d'éléments).

Voici. Espérons que cela clarifie et aide:

  NSSsortingng* searchSsortingng = @"AB0"; NSUInteger capacity = 1000000; NSMutableArray* array = [NSMutableArray array]; NSLog(@"Fillling array with %lu UUIDS. Be patient.", (unsigned long)capacity); NSUInteger batch = 0; for ( NSUInteger i = 0; i < capacity; i++ ) { [array setObject:[[NSUUID UUID] UUIDSsortingng] atIndexedSubscript:i]; if (i != 0 && i % (capacity / 10) == 0 ) { NSLog(@"Completed %lu%%", (unsigned long)++batch * 10); } } NSLog(@"Done."); NSPredicate* formatPredicate = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@ AND SELF.length > 3", searchSsortingng]; NSLog(@"Filtering with predicate: %@", formatPredicate); NSArray* formatArray = [array filteredArrayUsingPredicate:formatPredicate]; NSLog(@"Got %lu results.", formatArray.count); NSPredicate* blockPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { NSSsortingng* theSsortingng = evaluatedObject; return theSsortingng.length > 3 && [theSsortingng rangeOfSsortingng:searchSsortingng].location != NSNotFound; }]; NSLog(@"Filtering with predicate: %@", blockPredicate); NSArray* blockArray = [array filteredArrayUsingPredicate:blockPredicate]; NSLog(@"Got %lu results.", blockArray.count); 

PS: Je ne le ferais pas sur un téléphone si vous utilisez la ligne INT32_MAX gros numbers 🙂