2016-05-31 51 views
1

我一直在努力解決如何使用NSPredicate,但我正在努力研究如何使用「like」。使用NSPredicate過濾NSArray並找到類似的字符串

例如,可以說我有一個NSArray:

,我無意中搜索單詞「寧克」而不是「尼克」。

我可以使用NSPredicate返回一個包含對象「Nick」的數組嗎?

這是我到目前爲止已經試過:返回

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF like[cd] %@", @"nink"]; 

[array filterUsingPredicate:bPredicate]; 

空數組。

這是NSPredicate能夠或我在這裏浪費我的時間嗎?

+0

澄清你的問題:你正在尋找一種方法來匹配一個與謂詞不匹配的字符串?那麼「諾克」,「諾克」呢? –

+0

是的,即使搜索詞是nock或nonk,我也希望它返回暱稱。基本上像自動更正。 – Shayno

+1

因此,基本上,您需要一個謂詞,它返回搜索項的最低[Levenshtein Distance](https://en.wikipedia.org/wiki/Levenshtein_distance)(或類似度量)的關鍵字,是否正確? –

回答

2

你在找什麼是一個自定義謂詞,它使用有界的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); 
}]; 

該斷言定義了一個通用的謂詞的「模板」,然後您可以使用該濾鏡陣列實際字符串您正在尋找:

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]; 

BTW,沒有什麼特別之處的話@"key";您可以將其更改爲標識替換的任何字符串(例如,@"name",@"term"等都是有效的)。您在替換變量中提供的鍵是您應該用來檢索值的鍵。

+1

非常感謝,我不知道什麼Levenshtein距離,但它正是我需要的!我只需要在代碼中進行修改就可以在謂詞塊的開頭添加^ BOOL。此外,我將不得不玩弄matchGain和missingCost,讓它按照我的需要工作。 – Shayno