NSPredicate以匹配“NSDatabase中的任何条目与包含字符串的值” [英] NSPredicate to match "any entry in an NSDatabase with value that contains a string"

查看:88
本文介绍了NSPredicate以匹配“NSDatabase中的任何条目与包含字符串的值”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an array of dictionaries, similar to the following:


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

我想让用户能够在白色和黑色字段内或任何字段内搜索文本。我只有特定的字段才有NSPredicate:

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,它将返回第一个字典而不是第二个字典。我尝试了自我。*,我并没有真正期待工作,还有任何自我。值,我更加充满希望。我实际上并不事先知道密钥是什么,因此需要一些不太具体的东西。

I can't think of how to phrase a predicate that will return me the dictionaries for which any of the objects within match the text. i.e. I could search for "2007" and it would return the first dictionary but not the second. I tried "self.*" which I didn't really expect to work and also "ANY self.allValues" which I was more hopeful about. I don't actually know in advance what the keys will be, hence needing something less specific.

有什么建议吗?

推荐答案

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

If all of the dictionaries have the same set of keys, then you could do something pretty simple:

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

然后你可以使用过滤器过滤你的 NSArray (使用 -filteredArrayUsingPredicate )。

Then you can use filter to filter your NSArray (using -filteredArrayUsingPredicate).

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

If, on the other hand, you have an array of arbitrary dictionaries that all have different keys, you'd need to something a bit more perverse:

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

关于这是做什么:


  • FUNCTION(SELF,'allKeys') - 这将执行 -allKeys on SELF NSDictionary )并返回 NSArray 字典中的键

  • SUBQUERY(allKeys,$ k,SELF [$ k]包含[cd]%@) - 这将遍历 allKeys 中的每个项目,并将每个连续项目放入 $ k 变量中。对于每个项目,它将执行 SELF [$ k]包含%@ 。这基本上最终会做: [theDictionary objectForKey:$ k]包含[cd]%@ 。如果返回 YES ,那么 $ k 项将聚合成一个新数组。

  • SUBQUERY(...)。@ count> 0 - 在找到与包含搜索文本的值对应的所有键后,我们检查并查看是否有任何键。如果有(即,数组的大小大于0),那么整个字典将成为最终的过滤数组的一部分。

  • FUNCTION(SELF, 'allKeys') - this will execute -allKeys on SELF (an NSDictionary) and return an NSArray of all the keys in the dictionary
  • SUBQUERY(allKeys, $k, SELF[$k] contains[cd] %@) - This will iterate over every item in allKeys, with each successive item being placed into the $k variable. For each item, it will execute SELF[$k] contains %@. This will basically end up doing: [theDictionary objectForKey:$k] contains[cd] %@. If this returns YES, then the $k item will be aggregated into a new array.
  • SUBQUERY(...).@count > 0 - after finding all of the keys that correspond to values that contain your search text, we check and see if there were any. If there were (ie, the size of the array is larger than 0), then the overall dictionary will be part of the final, filtered array.

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

I recommend going with the first approach, if at all possible. SUBQUERY and FUNCTION are a bit arcane, and the first is much easier to understand.

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

And here's another way, which you actually almost had in your question. Instead of doing ANY SELF.allValues contains[cd] %@, you can do ANY FUNCTION(SELF, 'allValues') contains[cd] %@. This is equivalent to my SUBQUERY madness, but much simpler. Kudos to you for thinking of using ANY (I usually forget that it exists).

编辑

SELF.allValues 的原因不起作用,是这被解释为一个keypath,和 - [NSDictionary valueForKey:] 应该与相同 - [NSDictionary objectForKey:] 。这里的问题是,如果你在密钥前加上 @ ,那么它转发到 [super valueForKey:] ,哪个做你期望的事情。所以你真的可以做到:

The reason SELF.allValues doesn't work, is that this is interpreted as a keypath, and -[NSDictionary valueForKey:] is supposed to be the same as -[NSDictionary objectForKey:]. The catch here is that if you prefix the key with @, then it forwards on to [super valueForKey:], which will do what you're expecting. So you could really do:

ANY SELF.@allValues contains[cd] %@

或者只是:

ANY @allValues contains[cd] %@

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

And this will work (and is the best and simplest approach).

这篇关于NSPredicate以匹配“NSDatabase中的任何条目与包含字符串的值”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆