2010-10-25 12 views

risposta

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

Quindi, se sto leggendo questo correttamente, la logica in quel blocco di enumerazione è "Se' dict1' non contiene un oggetto per 'chiave' e l'oggetto' dict2' per 'chiave' è un dizionario, quindi unisci' dict1 '' s ​​oggetto per 'chiave' nell'oggetto' dict2' per 'chiave'" ... ma sappiamo già che 'dict1' non ha un oggetto per quel' chiave'. Quindi tutto ciò che sta facendo il blocco è l'aggiunta di oggetti da 'dict2' che non sono già in' dict1' in 'dict1'. – Mathew

+0

Penso che il primo controllo dell'enumerazione non sia corretto e debba essere rimosso. 'if (! [dict1 objectForKey: key])' lo rende così che nessuna chiave in dict2' ma non in dict1 non venga scritta. Forse è di design, ma se vuoi aggiungere delle chiavi univoche da 'dict2' non dovresti includere questo controllo. – atreat

+0

Grazie per questo, non ha funzionato abbastanza - ho fatto una piccola modifica - vedi http://stackoverflow.com/a/43172809/3346628 – pomo

7

Penso che questo sia quello che stai cercando:

In primo luogo, è necessario effettuare una copia profonda mutabile, in modo da poter creare una categoria sulla NSDictionary per fare questo:

@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 

Quindi, è possibile chiamare deepMutableCopy in questo modo:

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

E questo è ricorsivo? Anche in questo NSDictionaries negli NSDictionaries saranno uniti? –

+0

Penso che dovremmo anche sostituire "return temp;" con "return [temp autorelease];" e sostituisci "return (copy (self));" con "return [(copy (self)) retain];" per evitare perdite – AmineG

+0

@ someone0 '-mutableCopy' è implicito per restituire la proprietà al destinatario. Pertanto, non autorizziamo il valore di ritorno. –

4

ho aggiunto questo al codice di cui sopra. Potrebbe non essere completamente corretto, ma gestisce il caso in cui 2 dict ha un elemento che 1 dict non ha.

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

So che questa è una vecchia questione, ma ho bisogno di fare la stessa cosa: in modo ricorsivo unire due oggetti dizionario. Devo fare un ulteriore passo avanti e unire tutti gli oggetti che possono essere uniti in modo ricorsivo (l'obiettivo finale è quello di unire due dizionari creati da plists). Sto ospitando la mia soluzione al https://github.com/bumboarder6/NSDictionary-merge

Sto ancora lavorando al progetto, ma al momento sto già lavorando (in test limitati) per la fusione ricorsiva di dizionari. Arrays and Sets arriveranno presto.

Ho notato alcuni errori logici in alcune altre soluzioni che ho visto per questo problema e spero che evitassi quelle insidie, ma le critiche sono benvenute.

L'uso è semplice:

#import "NSMutableDictionary-merge.h" 

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

[dict1 mergeWithDictionary:dict2]; 
+0

Le mie scuse, sono stato interrotto mentre leggevo e, a quanto pare, non l'ho fatto in realtà finisci prima di commentare. – griotspeak

+0

Nessun problema. Ho intenzione di andare avanti e cancellare questa piccola interazione - non esattamente rilevante alla fine :) – Mathew

1

Sono venuto qui in cerca di una copia di jQuery di extend ma ho finito per scrivere la mia propria implementazione. È un'implementazione semplicissima, l'ho fatto quindi avrei capito un modo per farlo.

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

Speriamo che qualcuno lo trovi utile, ha funzionato nei miei test con una ricorsione profonda. Lo sto usando per estendere file JSON profondi pieni di testo.

+1

Modifica minore: 'BOOL hasValue = [baseDictionary objectForKey: key]! = Nil;' Altrimenti, funziona bene. – Rayfleck

+0

@Rayfleck Ho fatto questo aggiornamento - grazie –

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 funziona per me tranne il caso in cui dict2 contiene un dizionario mancante in dict1 - si blocca. Ho cambiato la logica in questo:

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