使用 NSPredicate 过滤 NSArray 并找到相似的字符串
Posted
技术标签:
【中文标题】使用 NSPredicate 过滤 NSArray 并找到相似的字符串【英文标题】:Using NSPredicate to filter NSArray and find similar strings 【发布时间】:2016-05-31 01:44:10 【问题描述】:我一直在努力研究如何使用 NSPredicate,但我正在努力研究如何使用“like”。
例如,假设我有一个 NSArray:
NSArray *array = [NSArray arrayWithObjects:@"Nick", @"Ben", @"Adam", @"Melissa", nil];
我不小心搜索到了“Nink”这个词而不是“Nick”。
我可以使用 NSPredicate 来返回一个包含对象“Nick”的数组吗?
这是我迄今为止尝试过的:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF like[cd] %@", @"nink"];
[array filterUsingPredicate:bPredicate];
返回一个空数组。
这是 NSPredicate 能够做到的事情,还是我在这里浪费时间?
【问题讨论】:
澄清您的问题:您正在寻找一种方法来匹配谓词不匹配的字符串? “诺克”、“诺克”呢? 是的,即使搜索词是 nock 或 nonk,我也希望它返回 nick。基本上像自动更正。 因此,本质上,您需要一个谓词,将具有最低 Levenshtein Distance(或类似指标)的键返回到搜索词,对吗? @ItaiFerber 是的,但只是在一定程度上,例如如果搜索词是 Trevor,我不想返回任何结果,因为 Trevor 与数组。 什么是“足够接近”? 【参考方案1】:您正在寻找的是一个自定义谓词,它使用有限的 Levenshtein 距离来过滤掉与目标词有很大差异的词。
假设您使用 in this gist 的 Levenshtein Distance 实现,您的代码将大致如下所示:
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"
等都有效)。您在替换变量中提供的键是您应该用来检索值的键。
【讨论】:
非常感谢,我不知道 Levenshtein 距离是多少,但这正是我所需要的!我需要更改代码以使其工作的唯一事情是在谓词块的开头添加 ^BOOL 。此外,我将不得不使用 matchGain 和 missingCost 才能让它按照我的需要工作。以上是关于使用 NSPredicate 过滤 NSArray 并找到相似的字符串的主要内容,如果未能解决你的问题,请参考以下文章
使用 NSPredicate 根据 NSDictionary 键过滤 NSArray
如何使用 NSPredicate 过滤这些 NSArray?
使用 NSpredicate 过滤 NSArray 的 Big-O 运行时