NSPredicate将“NSDatabase中的任何条目与包含字符串的值匹配”

时间:2011-04-06 16:11:59

标签: ios nsdictionary nspredicate

我有一系列词典,类似于以下内容:

(
        {
            Black = "?";
            Date = "????.??.??";
            Result = "*";
            SourceDate = "2007.10.24";
            White = "Mating pattern #1";
        },
        {
            Black = "?";
            Date = "????.??.??";
            Result = "*";
            SourceDate = "2008.10.24";
            White = "About this Publication";
        }
)

我希望为用户提供在“白色”和“黑色”字段内或任何字段内搜索文本的功能。我只有特定的领域才有NSPredicate:


    predicate = [NSPredicate 
                    predicateWithFormat:@"self.Black contains[cd] %@ or self.White contains[cd] %@",
                        searchText, searchText];
    [filteredGames addObjectsFromArray:[games filteredArrayUsingPredicate:predicate]];

我想不出如何用一个谓词来表示将返回与该文本匹配的任何对象的词典。即我可以搜索“2007”,它将返回第一个字典而不是第二个字典。我尝试了“自我。*”,我并没有真正期待工作,还有“任何self.allValues”,我更加充满希望。我实际上并不事先知道密钥是什么,因此需要一些不太具体的东西。

有什么建议吗?

2 个答案:

答案 0 :(得分:15)

如果所有词典都有相同的键集,那么你可以做一些非常简单的事情:

NSArray *keys = ...; //the list of keys that all of the dictionaries contain
NSMutableArray *subpredicates = [NSMutableArray array];
for (NSString *key in keys) {
  NSPredicate *subpredicate = [NSPredicate predicateWithFormat:@"%K contains[cd] %@", key, searchText];
  [subpredicates addObject:subpredicate];
}
NSPredicate *filter = [NSCompoundPredicate orPredicateWithSubpredicates:subpredicates];

然后,您可以使用filter来过滤NSArray(使用-filteredArrayUsingPredicate)。

另一方面,如果你有一个任意字典数组都有不同的键,你需要更多的东西:

NSPredicate *filter = [NSPredicate predicateWithFormat:@"SUBQUERY(FUNCTION(SELF, 'allKeys'), $k, SELF[$k] contains[cd] %@).@count > 0", searchText];

关于这是做什么的:

  • FUNCTION(SELF, 'allKeys') - 这将在-allKeys上执行SELFNSDictionary)并返回字典中所有键的NSArray
  • SUBQUERY(allKeys, $k, SELF[$k] contains[cd] %@) - 这将迭代allKeys中的每个项目,每个连续项目都放在$k变量中。对于每个项目,它将执行SELF[$k] contains %@。这基本上最终会做:[theDictionary objectForKey:$k] contains[cd] %@。如果返回YES,则$k项将聚合为新数组。
  • SUBQUERY(...).@count > 0 - 在找到与包含搜索文本的值对应的所有键后,我们会检查并查看是否有任何键。如果有(即,数组的大小大于0),那么整个字典将成为最终的过滤数组的一部分。

如果可能的话,我建议采用第一种方法。 SUBQUERYFUNCTION有点神秘,第一个很多更容易理解。


这是另一种方式,你实际上几乎在你的问题中。您可以执行ANY SELF.allValues contains[cd] %@,而无需执行ANY FUNCTION(SELF, 'allValues') contains[cd] %@。这相当于我的SUBQUERY疯狂,但更简单。感谢您考虑使用ANY(我通常会忘记它存在)。

修改

SELF.allValues不起作用的原因是,这被解释为一个关键路径,-[NSDictionary valueForKey:] is supposed to be the same as -[NSDictionary objectForKey:]。这里的问题是,如果您在密钥前加@,那么它会转发到[super valueForKey:] 会执行您期望的操作。所以你真的可以做到:

ANY SELF.@allValues contains[cd] %@

或者简单地说:

ANY @allValues contains[cd] %@

这将起作用(并且是最好和最简单的方法)。

答案 1 :(得分:0)

如果要匹配字典中的对象,可以使用for循环来完成此操作 这可能是一项耗时的任务 -

for(int i=0; i< [array count]; i++)
{

    NSDictionary *dic = [array objectAtIndex:i];

    if([[dic objectForKey:@"Black"] isEqualToString:@"2007"])
    {
    //here is the match
    }
}