【问题标题】:Using NSPredicate to filter NSArray and find similar strings使用 NSPredicate 过滤 NSArray 并找到相似的字符串
【发布时间】: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 与数组。
  • 什么是“足够接近”?

标签: ios objective-c nspredicate


【解决方案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 才能让它按照我的需要工作。
猜你喜欢
  • 2014-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-02
  • 1970-01-01
相关资源
最近更新 更多