ios - NSPredicate 匹配 "any entry in an NSDatabase with value that contains a string"

标签 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";
        }
)

I want to offer the user the ability to search for text either within just the "White" and "Black" fields, or within any field. I've got an NSPredicate for doing just the specific fields:


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

我想不出如何表达一个谓词,它会返回字典中的任何对象与文本匹配的字典。即我可以搜索“2007”,它会返回第一本字典而不是第二本。我尝试了“self.*”,我并没有真正期望它能工作,也尝试了“ANY self.allValues”,这是我更有希望的。我实际上事先并不知道键是什么,因此需要一些不太具体的东西。

有什么建议吗?

最佳答案

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

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 上执行 -allKeys(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),则整个字典将成为最终过滤数组的一部分。

如果可能的话,我建议使用第一种方法。 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:]。这里要注意的是,如果您在 key 前加上 @,它就会转发到 [super valueForKey:]执行您的操作正在期待。所以你真的可以这样做:

ANY SELF.@allValues contains[cd] %@

或者简单地说:

ANY @allValues contains[cd] %@

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

关于ios - NSPredicate 匹配 "any entry in an NSDatabase with value that contains a string",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5569632/

相关文章:

iOS - 如何强制两个标签具有相同的长度?

ios - 多个标记Google Map iOS SDK

objective-c - -[__NSArrayI replaceObjectAtIndex :withObject:]: unrecognized selector sent to instance

ios - NSPredicate 与字符串完全匹配

ios - 如何暂停在应用程序内播放的youtubevideo?

iphone - 我如何向分组的 UITableView 添加阴影(如官方 Twitter 应用程序所示)?

objective-c - NSDictionary 类的 JSONRepresentation 如何工作?

ios - 使用 NSDictionary 对象从数组中获取对象

swift - 检查字典是否包含 Swift 中的值

ios - onFormat string For NSPredicate