2010-10-25 46 views

回答

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

因此,如果我正确读取它,那么枚举块中的逻辑是“如果'dict1'不包含'key'的对象,并且'key'的dict2'对象是字典,则将'dict1 ''把'key'的对象转换成'dict2'的'key'的对象......“但是我们已经知道'dict1'没有那个'key'的对象。因此,该块所做的就是将来自'dict2'的任何对象都不是'dict1'中的对象添加到'dict1'中。 – Mathew 2013-02-05 19:33:03

+0

我认为你在枚举中的第一个检查是不正确的,应该删除。 'if(![dict1 objectForKey:key])'使得它在'dict2'中但不在dict1中的任何键都不会被写入。也许这是设计,但如果你想添加'dict2'中的任何唯一键,你不应该包含这个检查。 – atreat 2013-09-09 21:43:56

+0

感谢你,虽然没有完全工作 - 我做了一个小小的改变 - 见http://stackoverflow.com/a/43172809/3346628 – pomo 2017-04-02 19:49:58

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

这是递归?因为NSDictionaries中的NSDictionaries也会合并? – 2010-10-25 11:17:30

+0

我认为我们也应该取代“回归温度;”用“return [temp autorelease];”并替换“return(copy(self));”用“return [(copy(self))retain];”以避免泄漏 – AmineG 2012-02-17 10:20:48

+0

@ someone0'-mutableCopy'暗示将所有权返还给被调用者。因此,我们不会自动发布返回值。 – 2012-02-17 11:54:50

4

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

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

}

0

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

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

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

用法很简单:

#import "NSMutableDictionary-merge.h" 

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

[dict1 mergeWithDictionary:dict2]; 
+0

我的歉意,我在阅读时被打断,看起来,我没有实际完成评论之前。 – griotspeak 2013-02-05 19:25:29

+0

不用担心。我将继续并删除这个小交互 - 最终不完全相关:) – Mathew 2013-02-05 19:28:27

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文件。

+1

小修改:'BOOL hasValue = [baseDictionary objectForKey:key]!= nil;'否则,效果很好。 – Rayfleck 2015-07-16 16:00:09

+0

@Rayfleck我已经做了更新 - 谢谢 – 2015-07-20 10:35:54

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