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

mck*_*nut 6 nsdictionary nspredicate ios

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

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

Run Code Online (Sandbox Code Playgroud)

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

有什么建议?

Dav*_*ong 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];
Run Code Online (Sandbox Code Playgroud)

然后你可以filter用来过滤你的NSArray(使用-filteredArrayUsingPredicate).

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

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

关于这是做什么的一点:

  • FUNCTION(SELF, 'allKeys')- 这将-allKeysSELF(an NSDictionary)上执行并返回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不起作用,是这被解释为一个keypath,并且-[NSDictionary valueForKey:] 应该是相同的 -[NSDictionary objectForKey:].这里的问题是,如果你用密钥加前缀@,那么它就转发到[super valueForKey:],这做你期望的事情.所以你真的可以这样做:

ANY SELF.@allValues contains[cd] %@
Run Code Online (Sandbox Code Playgroud)

或者干脆:

ANY @allValues contains[cd] %@
Run Code Online (Sandbox Code Playgroud)

这将是有效的(并且是最好和最简单的方法).