Reputation: 24563
I have an array of "whitelisted" keys and I want to filter an NSDictionary based on those keys;
NSArray *whiteList = @["one", "two"];
NSDictionary *dictionary = @{
@"one" : @"yes",
@"two" : @"yes",
@"three" : @"no"
};
NSDictionary *whiteDictionary = [dictionary dictionaryWithValuesForKeys:whiteList];
Which produces:
{
one = "yes";
two = "yes;
}
However if my dictionary does not include one or more of the keys:
NSArray *whiteList = @["one", "two"];
NSDictionary *dictionary = @{
@"one" : @"yes"
};
NSDictionary *whiteDictionary = [dictionary dictionaryWithValuesForKeys:whiteList];
I get back:
{
one = "yes";
two = "<null>";
}
Is there a way to filter a dictionary based on a set of keys without getting keys that don't exist.
Upvotes: 1
Views: 2174
Reputation: 32775
Update
You could have a functional solution by filtering all keys of the original dictionary, and then building the whitelisted dictionary from the filtered keys list:
NSDictionary *whiteDictionary = [dictionary dictionaryWithValuesForKeys:[dictionary.allKeys filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self IN %@", whiteList]]];,
or in two lines, by declaring a separate variable for the predicate, to reduce the size of the line:
NSPredicate *whitelistPredicate = [NSPredicate predicateWithFormat:@"self IN %@", whiteList];
NSDictionary *whiteDictionary = [dictionary dictionaryWithValuesForKeys:[dictionary.allKeys filteredArrayUsingPredicate:whitelistPredicate]];,
Original answer
A semi-functional approach would look like this:
NSDictionary *whiteDictionary = [dictionary dictionaryWithValuesForKeys:whiteList];
whiteDictionary = [whiteDictionary dictionaryWithValuesForKeys:[whiteDictionary keysOfEntriesPassingTest:^(NSString *key, id obj, BOOL *stop) { return obj != [NSNull null]; }]];
Alternatively, you could enumerate through the dictionary and build-up the filtered dictionary:
NSMutableDictionary *whiteDictionary = [NSMutableDictionary dictionary];
[dictionary enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
if ([whiteList containsObject:key]) {
whiteDictionary[key] = obj;
}
}
Upvotes: 5
Reputation: 104
If you're not concerned with recursively doing it for collections inside the dictionary, something like this should work:
- (NSDictionary *)dictionaryWithNonNullValuesForKeys:(NSArray *)keys {
NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionary];
for (id key in keys) {
id value = self[key];
if ([value isKindOfClass:[NSNull class]]) {
NSLog(@"Warning, value for key was null, skipping key %@", key);
}
else {
mutableDictionary[key] = value;
}
}
return [mutableDictionary copy];
}
Upvotes: 1