深度结合NSDictionaries

时间:2010-10-25 03:43:44

标签: objective-c merge nsdictionary

我需要将两个NSDictionary合并为一个,前提是如果字典中有字典,它们也会被合并。

或多或少像jQuery的extend函数。

8 个答案:

答案 0 :(得分:30)

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

答案 1 :(得分:7)

我认为这就是你要找的东西:

首先,您需要制作深度可变副本,以便在NSDictionary上创建一个类别来执行此操作:

@implementation NSDictionary (DeepCopy)

- (id)deepMutableCopy
{
    id copy(id obj) {
        id temp = [obj mutableCopy];
        if ([temp isKindOfClass:[NSArray class]]) {
            for (int i = 0 ; i < [temp count]; i++) {
               id copied = [copy([temp objectAtIndex:i]) autorelease];
               [temp replaceObjectAtIndex:i withObject:copied];
            }
        } else if ([temp isKindOfClass:[NSDictionary class]]) {
            NSEnumerator *enumerator = [temp keyEnumerator];
            NSString *nextKey;
            while (nextKey = [enumerator nextObject])
                [temp setObject:[copy([temp objectForKey:nextKey]) autorelease]
                         forKey:nextKey];
        } 
        return temp;
    }

    return (copy(self));
}

@end

然后,您可以像这样致电deepMutableCopy

NSMutableDictionary *someDictionary = [someDict deepMutableCopy];
[someDictionary addEntriesFromDictionary:otherDictionary];

答案 2 :(得分:4)

我将此添加到上面提到的代码中。它可能不完全正确,但它处理2 dict有一个1 dict没有的元素的情况。

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

}

答案 3 :(得分:1)

我来到这里寻找jQuery的extend副本,但我最终编写了自己的实现。这是一个非常简单的实现,我做到了,所以我理解了一种方法。

+(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];
}

希望有人会发现这有用,它在我的测试中使用了深度递归。我用它来扩展充满文本的深JSON文件。

答案 4 :(得分:0)

我知道这是一个老问题,但我需要做同样的事情:递归合并两个字典对象。我需要更进一步,合并任何可以递归合并的对象(最终目标是合并从plists创建的两个词典)。我正在https://github.com/bumboarder6/NSDictionary-merge

主持我的解决方案

我仍在研究这个项目,但在撰写本文时,它已经可以(在有限的测试中)用于递归字典合并。数组和集即将推出。

我注意到我在这个问题上看到的一些其他解决方案中存在一些逻辑错误,我希望避免这些陷阱,但欢迎批评。

用法很简单:

#import "NSMutableDictionary-merge.h"

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

[dict1 mergeWithDictionary:dict2];

答案 5 :(得分:0)

#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

答案 6 :(得分:0)

Alexsander Akers为我工作,除了dict2包含dict1缺少的字典的情况 - 它崩溃了。我将逻辑改为:

+ (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];
}

答案 7 :(得分:0)

我需要一种将两个JSON对象中的对象递归合并(追加)的方法,重点关注其中的NSDictionaries,但同时考虑NSArrays,并优雅地处理类型不一致的情况。这里的其他答案没有那么远,因此我需要自己编写。以下处理所有这些情况。因为验证是在顶部而不是在中间,所以从混合的非null和nullable对象开始可用。将来可能会对其进行扩展以支持附加的附加类型。若要使用,请将xxx_前缀重命名为您自己的小写的三位数前缀。这是适当的,因为这是基础类的扩展:

NSObject + Append.h

@interface NSObject (Append)

+ (nullable id)xxx_objectAppendingObject1:(nullable id)object1 object2:(nullable id)object2 NS_SWIFT_NAME(kva_objectAppending(object1:object2:));


@end

NSObject + Append.m

@implementation NSObject (Append)


+ (nullable id)xxx_objectAppendingObject1:(nullable id)object1 object2:(nullable id)object2
{
    // VALIDATE ELSE RETURN
    if (object1 == nil)
    {
        return object2;
    }

    if (object2 == nil)
    {
        return object1;
    }

    // MAIN
    // dictionary1
    NSDictionary *dictionary1 = [object1 isKindOfClass:NSDictionary.class] ? (NSDictionary *)object1 : nil;
    
    // dictionary2
    NSDictionary *dictionary2 = [object2 isKindOfClass:NSDictionary.class] ? (NSDictionary *)object2 : nil;
    
    // array1
    NSArray *array1 = [object1 isKindOfClass:NSArray.class] ? (NSArray *)object1 : nil;
    
    // array2
    NSArray *array2 = [object2 isKindOfClass:NSArray.class] ? (NSArray *)object2 : nil;
    
    // A. NSDICTIONARY TO NSDICTIONARY
    if ((dictionary1 != nil) && (dictionary2 != nil))
    {
        NSMutableDictionary *returnDictionary = dictionary1.mutableCopy;
        [dictionary2 enumerateKeysAndObjectsUsingBlock: ^(id key, id obj, BOOL *stop)
        {
            returnDictionary[key] = [self.class kva_objectAppendingObject1:dictionary1[key] object2:obj];
        }];
        return returnDictionary;
    }

    // B. NSARRAY TO NSARRAY
    if ((array1 != nil) && (array2 != nil))
    {
        return [array1.mutableCopy arrayByAddingObjectsFromArray:array2];
    }

    // DEFAULT
    return object2;
}

@end