Deep combine NSDictionaries

2019-01-14 03:15发布

I need to merge two NSDictionarys into one provided that if there are dictionaries within the dictionaries, they are also merged.

More or less like jQuery's extend function.

7条回答
成全新的幸福
2楼-- · 2019-01-14 03:38

I know this is an old question, but I need to do the same thing: recursively merge two dictionary objects. I need to go a step further and merge any objects that can be merged recursively (the end goal is merging two dictionaries created from plists). I am hosting my solution at https://github.com/bumboarder6/NSDictionary-merge

I am still working on the project, but as of this writing it already works (in limited testing) for recursive dictionary merging. Arrays and Sets are coming soon.

I noticed a few logic errors in some other solutions I have seen for this problem and I hopefully avoided those pitfalls, but critiques are welcome.

Usage is simple:

#import "NSMutableDictionary-merge.h"

NSMutableDictionary* dict1 = [NSMutableDictionary ...];
NSDictionary* dict2 = [NSDictionary ...];

[dict1 mergeWithDictionary:dict2];
查看更多
成全新的幸福
3楼-- · 2019-01-14 03:41

I came here looking for a copy of jQuery's extend but I ended up writing my own implementation. It's a super simple implementation, I did it so I'd understand a way to do it.

+(NSDictionary*) dictionaryByExtending:(NSDictionary*)baseDictionary WithDictionary:(NSDictionary*)extensionDictionary {

    NSMutableDictionary * resultDictionary = [NSMutableDictionary dictionaryWithDictionary:baseDictionary];

    [extensionDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {

        BOOL isDict = [obj isKindOfClass:[NSDictionary class]];
        BOOL hasValue = [baseDictionary hasObjectForKey:key] != nil;

        id setObj = obj;

        if( hasValue && isDict ) {

            BOOL hasDict = [[baseDictionary objectForKey:key] isKindOfClass:[NSDictionary class]];

            if( hasDict ) {

                NSDictionary * extendedChildDictionary = [NSDictionary dictionaryByExtending:[baseDictionary objectForKey:key] WithDictionary:obj];
                setObj = extendedChildDictionary;

            }

        }

        [resultDictionary setObject:setObj forKey:key];

    }];

    return resultDictionary;

}

-(NSDictionary*) dictionaryByExtendingWithDictionary:(NSDictionary*)extensionDictionary {
    return [NSDictionary dictionaryByExtending:self WithDictionary:extensionDictionary];
}

Hopefully someone will find this helpful, it worked in my tests with deep-recursion. I'm using it to extend deep JSON files full of text.

查看更多
劳资没心,怎么记你
4楼-- · 2019-01-14 03:46

I added this to the code mentioned above. It may not be fully correct, but it handles the case where 2 dict has an element that 1 dict does not.

+ (NSDictionary *) dictionaryByMerging: (NSDictionary *) dict1 with: (NSDictionary *) dict2 {
    NSMutableDictionary * result = [NSMutableDictionary dictionaryWithDictionary:dict1];
    NSMutableDictionary * resultTemp = [NSMutableDictionary dictionaryWithDictionary:dict1];

    [resultTemp addEntriesFromDictionary:dict2];

    [resultTemp enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) {
    if ([dict1 objectForKey:key]) {
        if ([obj isKindOfClass:[NSDictionary class]]) {
            NSDictionary * newVal = [[dict1 objectForKey: key] dictionaryByMergingWith: (NSDictionary *) obj];
            [result setObject: newVal forKey: key];
        } else {
            [result setObject: obj forKey: key];
        }
    }
    else if([dict2 objectForKey:key])
    {
        if ([obj isKindOfClass:[NSDictionary class]]) {
            NSDictionary * newVal = [[dict2 objectForKey: key] dictionaryByMergingWith: (NSDictionary *) obj];
            [result setObject: newVal forKey: key];
        } else {
            [result setObject: obj forKey: key];
        }
    }
}];

return (NSDictionary *) [[result mutableCopy] autorelease];

}

查看更多
Luminary・发光体
5楼-- · 2019-01-14 03:50
#import "NSDictionary+Merge.h"

@implementation NSDictionary (Merge)

+ (NSDictionary *)dictionaryByMerging:(NSDictionary *)src with:(NSDictionary *)new
{
    NSMutableDictionary *result = [src mutableCopy];
    [new enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        if ([obj isKindOfClass:[NSDictionary class]]
            && [src[key] isKindOfClass:[NSDictionary class]]) {

            result[key] = [src[key] dictionaryByMergingWith:obj];
        } else {
            result[key] = obj;
        }
    }];
    return [NSDictionary dictionaryWithDictionary:result];
}

- (NSDictionary *)dictionaryByMergingWith:(NSDictionary *)dict {
    return [[self class] dictionaryByMerging:self with:dict];
}

@end
查看更多
smile是对你的礼貌
6楼-- · 2019-01-14 03:52

NSDictionary+Merge.h

#import <Foundation/Foundation.h>

@interface NSDictionary (Merge)

+ (NSDictionary *) dictionaryByMerging: (NSDictionary *) dict1 with: (NSDictionary *) dict2;
- (NSDictionary *) dictionaryByMergingWith: (NSDictionary *) dict;

@end

NSDictionary+Merge.m

#import "NSDictionary+Merge.h"

@implementation NSDictionary (Merge)

+ (NSDictionary *) dictionaryByMerging: (NSDictionary *) dict1 with: (NSDictionary *) dict2 {
    NSMutableDictionary * result = [NSMutableDictionary dictionaryWithDictionary:dict1];

[dict2 enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) {
    if (![dict1 objectForKey:key]) {
        if ([obj isKindOfClass:[NSDictionary class]]) {
            NSDictionary * newVal = [[dict1 objectForKey: key] dictionaryByMergingWith: (NSDictionary *) obj];
            [result setObject: newVal forKey: key];
        } else {
            [result setObject: obj forKey: key];
        }
    }
}];

    return (NSDictionary *) [[result mutableCopy] autorelease];
}
- (NSDictionary *) dictionaryByMergingWith: (NSDictionary *) dict {
    return [[self class] dictionaryByMerging: self with: dict];
}

@end
查看更多
疯言疯语
7楼-- · 2019-01-14 03:54

Alexsander Akers works for me except the case where dict2 contains a dictionary that's missing from dict1 - it crashes. I changed the logic to this:

+ (NSDictionary *) dictionaryByMerging: (NSDictionary *) dict1 with: (NSDictionary *) dict2 {
    NSMutableDictionary * result = [NSMutableDictionary dictionaryWithDictionary:dict1];

    [dict2 enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop) {
        if (![dict1 objectForKey:key]) {
            [result setObject: obj forKey: key];
        } else if ([obj isKindOfClass:[NSDictionary class]]) {
            NSDictionary * newVal = [[dict1 objectForKey: key] dictionaryByMergingWith: (NSDictionary *) obj];
            [result setObject: newVal forKey: key];
        }
    }];

    return (NSDictionary *) [result mutableCopy];
}
查看更多
登录 后发表回答