使用 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"
等都是有效的)。您在替换变量中提供的键是您应该用来检索值的键。
我一直在努力研究如何使用 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"
等都是有效的)。您在替换变量中提供的键是您应该用来检索值的键。