NSPredicate 匹配“NSDatabase 中的任何条目与包含字符串的值”
Posted
技术标签:
【中文标题】NSPredicate 匹配“NSDatabase 中的任何条目与包含字符串的值”【英文标题】:NSPredicate to match "any entry in an NSDatabase with value that contains a string" 【发布时间】:2011-04-06 16:11:59 【问题描述】:我有一个字典数组,类似于以下内容:
( 黑色=“?”; 日期 = "????.??.??"; 结果 = "*"; SourceDate = "2007.10.24"; 白色 = "交配模式 #1"; , 黑色=“?”; 日期 = "????.??.??"; 结果 = "*"; SourceDate = "2008.10.24"; White = "关于本出版物"; )我想让用户能够在“白色”和“黑色”字段内或任何字段内搜索文本。我有一个 NSPredicate 来处理特定的字段:
predicate = [NSPredicate
predicateWithFormat:@"self.Black contains[cd] %@ or self.White contains[cd] %@",
searchText, searchText];
[filteredGames addObjectsFromArray:[games filteredArrayUsingPredicate:predicate]];
我想不出如何表达一个谓词,它会返回与文本匹配的任何对象的字典。即我可以搜索“2007”,它会返回第一个字典而不是第二个。我尝试了“self.*”,但我并没有真正期望它会起作用,还尝试了“ANY self.allValues”,我对此更有希望。我实际上并不事先知道键是什么,因此需要一些不太具体的东西。
有什么建议吗?
【问题讨论】:
【参考方案1】:如果所有字典都有相同的键集,那么你可以做一些非常简单的事情:
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')
- 这将在 SELF
(NSDictionary
)上执行 -allKeys
并返回字典中所有键的 NSArray
SUBQUERY(allKeys, $k, SELF[$k] contains[cd] %@)
- 这将遍历allKeys
中的每个项目,并将每个连续项目放入$k
变量中。对于每个项目,它将执行SELF[$k] contains %@
。这基本上最终会做:[theDictionary objectForKey:$k] contains[cd] %@
。如果这返回YES
,那么$k
项将被聚合到一个新数组中。
SUBQUERY(...).@count > 0
- 在找到与包含您的搜索文本的值相对应的所有键之后,我们会检查是否有任何键。如果有(即数组的大小大于 0),则整个字典将成为最终过滤数组的一部分。
如果可能的话,我建议采用第一种方法。 SUBQUERY
和 FUNCTION
有点晦涩难懂,第一个更容易理解。
这是另一种方式,实际上您几乎已经在您的问题中提出了这种方式。除了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] %@
这将起作用(并且是最好和最简单的方法)。
【讨论】:
嗨,感谢您的深入回复 :-) 字典之间的标题集不一定相同,因此我无法使用您提到的第一种方法。其他看起来不错,但我已经尝试了最后一个,据我所知,如果我搜索任何过滤器,我会遇到异常。即,如果我搜索所有字典中存在的单个字母,它可以工作,其他任何东西都失败了,我得到:***由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“不能在/中使用”包含具有集合 0 的运算符(不是集合)' @mcknut 您能否在有关字典中数据的问题中提供更多信息,以及它如何引发该异常的具体示例? 如果我搜索“!”则会出现异常这在字典中是相当罕见的。我实际上在想“我做错了”,我应该改用 Core Data。在那种情况下,我会将键和值存储在它们自己的实体中,并带有对父实体的引用,然后搜索键和值实体以找到匹配项,我认为这是最好的。 @mcknut 搜索!
对我有用...你能在问题中发布更多代码吗?
抱歉,我现在重写了代码以使用 Core Data!感谢您的帮助,已将此解决方案标记为已接受。【参考方案2】:
如果你想匹配字典中的一个对象,你可以使用 for 循环来做到这一点,但是 这可能是一项耗时的任务 -
for(int i=0; i< [array count]; i++)
NSDictionary *dic = [array objectAtIndex:i];
if([[dic objectForKey:@"Black"] isEqualToString:@"2007"])
//here is the match
【讨论】:
以上是关于NSPredicate 匹配“NSDatabase 中的任何条目与包含字符串的值”的主要内容,如果未能解决你的问题,请参考以下文章