使用 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 运行时

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

使用NSPredicate过滤字符串为空的NSArray

使用 NSPredicate 过滤以数字或符号开头的字符串到 NSArray