2011-04-06 56 views
6

“与值包含字符串在NSDatabase任何条目”我有字典的数组,类似以下内容: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”,我更加希望。事实上我并没有事先知道钥匙是什么,因此需要一些不太具体的东西。

有什么建议吗?

回答

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] %@)[email protected] > 0", searchText]; 

什么,这是做了一些:

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

我建议要采用第一种方法,如果可能的话。 SUBQUERYFUNCTION都有点神秘,并且第一个是多了比较容易理解。


而这里的另一种方式,你居然差点就在你的问题。而不是做ANY SELF.allValues contains[cd] %@,你可以做ANY FUNCTION(SELF, 'allValues') contains[cd] %@。这相当于我的SUBQUERY疯狂,但更简单。对于使用ANY(我通常会忘记它存在)的想法而感到赞叹。

编辑

原因SELF.allValues不工作,是这被解释为的keyPath和-[NSDictionary valueForKey:]is supposed to be the same as-[NSDictionary objectForKey:]。这里的问题是,如果你在@前加了密钥,那么它就转发到[super valueForKey:]做你所期望的。所以,你可以真正做到:

ANY [email protected] contains[cd] %@ 

或者干脆:

ANY @allValues contains[cd] %@ 

,这将工作(和是最好的,最简单的方法)。

+0

嗨,感谢您的深入回复:-) 字典集不一定会在字典之间相同,所以我不能使用您提到的第一种方法。 其他看起来不错,但我已经去了最后一个,据我所知,如果我搜索任何过滤器,我会得到一个例外。即如果我搜索出现在所有字典中的单个字母,它可以工作,其他任何和它失败,我得到: ***由于未捕获异常“NSInvalidArgumentException”,终止应用程序,原因:'无法使用in /包含运算符与集合0(不是集合)' – mcknut 2011-04-06 19:45:51

+0

@mcknut您可以在有关字典中的数据的问题中提供更多信息,以及它如何引发异常的具体示例? – 2011-04-06 20:11:15

+0

如果我搜索“!”,则会发生异常这在字典中是相当罕见的。我实际上认为“我做错了”,我应该改用核心数据。在这种情况下,我会将Keys和Values存储在自己的实体中,并将​​其引用回父实体,然后搜索关键字和值实体以查找匹配项,我认为这将是最好的。 – mcknut 2011-04-06 23:20:28

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 
    } 
} 
+0

嗨,谢谢,但我真的希望避免这样做。 – mcknut 2011-04-06 19:47:03

相关问题