我一直在尝试研究如何使用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能够做到的事情,还是我在这里浪费时间?
答案 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"
等,都是有效的)。您在替换变量中提供的密钥是您应该用来检索值的密钥。