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

Using NSPredicate to filter NSArray and find similar strings

我一直在努力研究如何使用 NSPredicate,但我正在努力研究如何使用 "like"。

例如,假设我有一个 NSArray:

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

我不小心搜索了 "Nink" 而不是 "Nick"。

我可以使用 NSPredicate 来 return 一个包含对象 "Nick" 的数组吗?

这是我目前尝试过的方法:

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

[array filterUsingPredicate:bPredicate];

return编辑了一个空数组。

这是 NSPredicate 的能力还是我在这里浪费时间?

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

假设您使用发现的 Levenshtein 距离的实现 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);
}];

此谓词定义了一个通用谓词 "template",然后您可以使用它来过滤包含您要查找的实际字符串的数组:

    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" 等都是有效的)。您在替换变量中提供的键是您应该用来检索值的键。