Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>If all of the dictionaries have the same set of keys, then you could do something pretty simple:</p> <pre><code>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]; </code></pre> <p>Then you can use <code>filter</code> to filter your <code>NSArray</code> (using <code>-filteredArrayUsingPredicate</code>).</p> <p>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:</p> <pre><code>NSPredicate *filter = [NSPredicate predicateWithFormat:@"SUBQUERY(FUNCTION(SELF, 'allKeys'), $k, SELF[$k] contains[cd] %@).@count &gt; 0", searchText]; </code></pre> <p>A bit about what this is doing:</p> <ul> <li><code>FUNCTION(SELF, 'allKeys')</code> - this will execute <code>-allKeys</code> on <code>SELF</code> (an <code>NSDictionary</code>) and return an <code>NSArray</code> of all the keys in the dictionary</li> <li><code>SUBQUERY(allKeys, $k, SELF[$k] contains[cd] %@)</code> - This will iterate over every item in <code>allKeys</code>, with each successive item being placed into the <code>$k</code> variable. For each item, it will execute <code>SELF[$k] contains %@</code>. This will basically end up doing: <code>[theDictionary objectForKey:$k] contains[cd] %@</code>. If this returns <code>YES</code>, then the <code>$k</code> item will be aggregated into a new array.</li> <li><code>SUBQUERY(...).@count &gt; 0</code> - 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.</li> </ul> <p>I recommend going with the first approach, if at all possible. <code>SUBQUERY</code> and <code>FUNCTION</code> are a bit arcane, and the first is <em>much</em> easier to understand.</p> <hr> <p>And here's another way, which you actually almost had in your question. Instead of doing <code>ANY SELF.allValues contains[cd] %@</code>, you can do <code>ANY FUNCTION(SELF, 'allValues') contains[cd] %@</code>. This is equivalent to my <code>SUBQUERY</code> madness, but much simpler. Kudos to you for thinking of using <code>ANY</code> (I usually forget that it exists).</p> <p><strong>EDIT</strong></p> <p>The reason <code>SELF.allValues</code> doesn't work, is that this is interpreted as a keypath, and <code>-[NSDictionary valueForKey:]</code> <a href="http://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/Reference/Reference.html#//apple_ref/doc/uid/20000140-BBCIBCDJ" rel="noreferrer">is supposed to be the same as</a> <code>-[NSDictionary objectForKey:]</code>. The catch here is that if you prefix the key with <code>@</code>, then it forwards on to <code>[super valueForKey:]</code>, which <em>will</em> do what you're expecting. So you could really do:</p> <pre><code>ANY SELF.@allValues contains[cd] %@ </code></pre> <p>Or simply:</p> <pre><code>ANY @allValues contains[cd] %@ </code></pre> <p>And this will work (and is the best and simplest approach).</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload