2010-10-25 22 views

Trả lời

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

Vì vậy, nếu tôi đọc chính xác, logic trong khối liệt kê đó là "Nếu' dict1' không chứa đối tượng cho đối tượng 'key' và' dict2' cho 'khóa' là từ điển, sau đó hợp nhất' dict1 '' s ​​đối tượng cho 'key' vào đối tượng' dict2' cho 'key'" ... nhưng chúng ta đã biết rằng 'dict1' không có đối tượng cho' khóa' đó. Vì vậy, tất cả những gì khối đang làm là thêm bất kỳ đối tượng nào từ 'dict2' chưa có trong' dict1' vào 'dict1'. – Mathew

+0

Tôi nghĩ rằng kiểm tra đầu tiên của bạn trong liệt kê là không chính xác và cần được loại bỏ. 'if (! [dict1 objectForKey: key])' làm cho nó như vậy bất kỳ phím nào trong 'dict2' nhưng không phải trong dict1 sẽ không được viết. Có lẽ đó là do thiết kế, nhưng nếu bạn muốn thêm bất kỳ khóa duy nhất từ ​​'dict2' bạn không nên bao gồm kiểm tra này. – atreat

+0

Cảm ơn vì điều này, đã không làm việc khá mặc dù - Tôi đã thực hiện một thay đổi nhỏ - xem http://stackoverflow.com/a/43172809/3346628 – pomo

7

Tôi nghĩ rằng đây là những gì bạn đang tìm kiếm:

Trước tiên, bạn cần phải thực hiện một sâu bản sao có thể thay đổi, vì vậy bạn có thể tạo ra một thể loại trên NSDictionary để làm điều này:

@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 

Sau đó, bạn có thể gọi deepMutableCopy như thế này:

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

Và điều này là đệ quy? Trong đó NSDictionaries trong NSDictionaries cũng sẽ được sáp nhập? –

+0

Tôi nghĩ chúng ta cũng nên thay thế "return temp;" với "return [temp autorelease];" và thay thế "return (copy (self));" với "return [(copy (self)) giữ lại];" để tránh rò rỉ – AmineG

+0

@ someone0 '-mutableCopy' được ngụ ý trả lại quyền sở hữu trở lại callee. Do đó, chúng tôi không tự động trả lại giá trị trả về. –

4

tôi thêm này để mã nêu trên. Nó có thể không hoàn toàn chính xác, nhưng nó xử lý các trường hợp mà 2 dict có một yếu tố mà 1 dict không.

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

Tôi biết đây là một câu hỏi cũ, nhưng tôi cần phải làm điều tương tự: đệ quy hợp nhất hai đối tượng từ điển. Tôi cần phải đi thêm một bước nữa và hợp nhất bất kỳ đối tượng nào có thể được hợp nhất đệ quy (mục tiêu cuối cùng là kết hợp hai từ điển được tạo từ plists). Tôi đang lưu trữ giải pháp của mình tại https://github.com/bumboarder6/NSDictionary-merge

Tôi vẫn đang làm việc trên dự án, nhưng khi viết bài này, nó đã hoạt động (trong thử nghiệm giới hạn) để hợp nhất từ ​​điển đệ quy. Mảng và Bộ sắp có.

Tôi nhận thấy một vài lỗi logic trong một số giải pháp khác mà tôi đã thấy cho vấn đề này và tôi hy vọng tránh được những cạm bẫy đó, nhưng những lời phê bình được hoan nghênh.

Cách sử dụng rất đơn giản:

#import "NSMutableDictionary-merge.h" 

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

[dict1 mergeWithDictionary:dict2]; 
+0

Lời xin lỗi của tôi, tôi đã bị gián đoạn trong khi đọc và, có vẻ như, tôi đã không thực sự kết thúc trước khi nhận xét. – griotspeak

+0

Không phải lo lắng. Tôi sẽ tiếp tục và xóa tương tác nhỏ này - không chính xác liên quan đến kết thúc :) – Mathew

1

Tôi đến đây tìm kiếm một bản sao của jQuery extend nhưng tôi đã kết thúc bằng văn bản thực hiện của riêng tôi. Đó là một thực hiện siêu đơn giản, tôi đã làm nó vì vậy tôi muốn hiểu một cách để làm điều đó.

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

Hy vọng ai đó sẽ thấy điều này hữu ích, nó hoạt động trong các thử nghiệm của tôi với đệ quy sâu. Tôi đang sử dụng nó để mở rộng các tệp JSON sâu đầy văn bản.

+1

Thay đổi nhỏ: 'BOOL hasValue = [baseDictionary objectForKey: key]! = Nil;' Nếu không, hoạt động tốt. – Rayfleck

+0

@Rayfleck Tôi đã thực hiện cập nhật đó - cảm ơn bạn –

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 làm việc cho tôi ngoại trừ trường hợp dict2 chứa từ điển thiếu từ dict1 - nó bị treo. Tôi đã thay đổi logic này:

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