2010-10-25 14 views

Odpowiedz

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

Tak więc, jeśli czytam to poprawnie, logika w tym bloku wyliczania to "Jeśli' dict1' nie zawiera obiektu dla 'key' a obiekt' dict2' dla 'key' jest słownikiem, a następnie scal" dict1 " '' 'obiekt dla' klucza' do obiektu 'dict2' dla' klucza' "... ale wiemy już, że' dict1' nie ma obiektu dla tego 'klucza'. A więc wszystko, co robi blok, to dodawanie dowolnych obiektów z 'dict2', które nie są jeszcze w' dict1' do 'dict1'. – Mathew

+0

Myślę, że twoje pierwsze sprawdzenie w wyliczeniu jest nieprawidłowe i powinno zostać usunięte. 'if (! [dict1 objectForKey: key])' sprawia, że ​​wszystkie klucze, które są w 'dict2', ale nie w dict1, nie zostaną zapisane. Być może jest to zgodne z projektem, ale jeśli chcesz dodać unikalne klucze z 'dict2', nie powinieneś uwzględniać tego czeku. – atreat

+0

Dzięki za to, niezupełnie działałam - dokonałem niewielkiej zmiany - zobacz http://stackoverflow.com/a/43172809/3346628 – pomo

7

myślę, że to jest to, czego szukasz:

Po pierwsze, trzeba dokonać głęboki zmienny kopię, więc można utworzyć kategorię na NSDictionary to zrobić:

@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 

Następnie można nazwać deepMutableCopy takiego:

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

A to jest rekurencyjne? W tym NSDictionaries w NSDictionaries będą również połączone? –

+0

Myślę, że powinniśmy również zastąpić "temp powrotu" z "return [temp autorelease];" i zastąp "return (copy (self))" z "return [(copy (self)) retain];" aby uniknąć przecieków – AmineG

+0

@ someone0 '-mutableCopy' ma na celu zwrócenie własności z powrotem do adresata. W związku z tym nie zwracamy automatycznie wartości zwracanej. –

4

I dodaje to do kodu wspomnianego powyżej. Może nie być w pełni poprawny, ale obsługuje przypadek, w którym 2 dyktuje element, którego nie ma dyktator.

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

wiem, że to jest stare pytanie, ale muszę zrobić to samo: rekurencyjnie scalić dwa słownika obiektów. Muszę pójść o krok dalej i scalić dowolne obiekty, które mogą być scalone rekurencyjnie (celem końcowym jest połączenie dwóch słowników utworzonych z plists). Hostuję moje rozwiązanie pod https://github.com/bumboarder6/NSDictionary-merge

Nadal pracuję nad projektem, ale od tego pisania już działa (w ograniczonym testowaniu) do rekurencyjnego łączenia słownika. Arrays i zestawy już wkrótce.

Zauważyłem kilka błędów logicznych w niektórych innych rozwiązaniach, które widziałem w odniesieniu do tego problemu, i mam nadzieję, że uniknąłem tych pułapek, ale mile widziana jest krytyka.

użycia jest prosty:

#import "NSMutableDictionary-merge.h" 

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

[dict1 mergeWithDictionary:dict2]; 
+0

Przepraszam, zostałem przerwany podczas czytania i, jak się wydaje, nie zrobiłem faktycznie kończy się przed komentowaniem. – griotspeak

+0

Bez obaw. Zamierzam iść dalej i usunąć tę małą interakcję - niezupełnie trafną na końcu :) – Mathew

1

Przyjechałem tu w poszukiwaniu kopii jQuery extend ale skończyło się na piśmie własną implementację. To bardzo prosta implementacja, zrobiłem to, więc zrozumiałem sposób na zrobienie tego.

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

Mam nadzieję, że ktoś znajdzie to pomocne, zadziałało w moich testach z głęboką rekurencją. Używam go do rozszerzania głębokich plików JSON pełnych tekstu.

+1

Niewielka zmiana: 'BOOL hasValue = [baseDictionary objectForKey: key]! = Nil;' W przeciwnym razie działa dobrze. – Rayfleck

+0

@Rayfleck Dokonałem tej aktualizacji - dziękuję –

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 pracuje dla mnie z wyjątkiem przypadku, gdy dict2 zawiera słownik, którego brakuje w dict1 - ulega awarii. Zmieniłem logikę na:

+ (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]; 
} 
Powiązane problemy