lostintranslation
lostintranslation

Reputation: 24563

Filter NSDictionary based on array of keys

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

Answers (2)

Cristik
Cristik

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

NSIRLConnection
NSIRLConnection

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

Related Questions