2010-10-25 86 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]; 
}