使用NSPredcate筛选大型NSArray



我有一个数组,包含170k个字符串(字典中的单词(和一个字符串,看起来像"glapplega"。我正试图从字符串中提取单词"apple"(其中"apple"是数组中的一个单词(。我还需要确保提取的单词至少有3个字符。我现在的代码如下:

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

长度谓词独立工作,但单词谓词不工作(它返回一个空数组,尽管"apple"是数组中的一个单词(。

我怀疑在谓词中使用SELF作为右表达式可能有问题,因为我发现的所有示例都将其作为左表达式,尽管我无法证实这一点。

编辑:我知道这可能可以通过regexs(如本文所述(来实现,但我希望有办法解决这个问题,因为regexs在如此大的数据集中可能会很慢。

如果您自己使用块谓词迭代数组,那么解决这个问题很容易。在某种程度上,格式化的NSPredcate必须归结为这一点,因此不应该对性能造成太大影响。-[NSString rangeOfString:]可用于测试是否包含字符串。

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

您知道上面的假设和谓词是完全有效的。你唯一做错的就是引用。重新格式化你的谓词并使其像这样,

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

指定格式并将字符串提供给该格式时,谓词会自行放置引号。所以,你在这里搞错了。

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

输出:

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

您可以尝试两个选项来定义谓词。一个格式字符串和一个块。下面是一段演示这两者的代码。我和他们都打过球,可以分享他们的表现是一样的。我只有耐心在最大值为INT32_max/2(很多项目(的情况下运行它。

给。希望这能澄清并有所帮助:

    NSString* searchString = @"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] UUIDString] 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", searchString];
    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) {
        NSString* theString = evaluatedObject;
        return theString.length > 3 && [theString rangeOfString:searchString].location != NSNotFound;
    }];
    NSLog(@"Filtering with predicate: %@", blockPredicate);
    NSArray* blockArray = [array filteredArrayUsingPredicate:blockPredicate];
    NSLog(@"Got %lu results.", blockArray.count);

附言:如果你使用的是大数字行INT32_MAX:(

,我不会在手机上运行这个

最新更新