使用NSPredicate过滤NSArray并找到类似的字符串

时间:2016-05-31 01:44:10

标签: ios objective-c nspredicate

我一直在尝试研究如何使用NSPredicate,但我正在努力研究如何使用"喜欢"。

例如,假设我有一个NSArray:

NSArray *array = [NSArray arrayWithObjects:@"Nick", @"Ben", @"Adam", @"Melissa", nil];

我不小心搜索了“#34; Nink"而不是"尼克"。

我可以使用NSPredicate返回带有对象的数组" Nick"?

这是我到目前为止所尝试的:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF like[cd] %@", @"nink"];

[array filterUsingPredicate:bPredicate];

返回一个空数组。

这是NSPredicate能够做到的事情,还是我在这里浪费时间?

1 个答案:

答案 0 :(得分:2)

您正在寻找的是一个自定义谓词,它使用有界Levenshtein距离来过滤掉与目标词完全不同的词。

假设你使用Levenshtein Distance的实现in this gist,你的代码看起来大致如下:

NSPredicate *distancePredicate = [NSPredicate predicateWithBlock:^(NSString *name, NSDictionary<NSString *, id> *bindings) {
    // key is the string you're looking for (e.g. 'nink')
    NSString *key = bindings[@"key"];

    // Calculate the Levenshtein Distance. This may be different depending
    // on how you implement it. You may want to weight matchGain and
    // missingCost differently.
    NSInteger score = [key compareWithWord:name matchGain:0 missingCost:1];

    // Only include words that are "close enough", i.e. within two a letter
    // difference.
    return (BOOL)(score < 2);
}];

此谓词定义了一个通用谓词“模板”,然后您可以使用该模板使用您要查找的实际字符串过滤数组:

    NSDictionary<NSString *, id> *bindings = @{@"key": @"Nink"};
    NSMutableArray *array = [NSMutableArray arrayWithObjects:@"Nick", @"Ben", @"Adam", @"Melissa", nil];
    NSIndexSet *indices = [array indexesOfObjectsPassingTest:^(id object, NSUInteger index, BOOL *stop) {
        return [distancePredicate evaluateWithObject:object substitutionVariables:bindings];
    }];

    NSArray *results = [array objectsAtIndexes:indices];
顺便说一句,@"key"这个词没有什么特别之处;您可以将其更改为标识替换的任何字符串(例如@"name"@"term"等,都是有效的)。您在替换变量中提供的密钥是您应该用来检索值的密钥。