Como você adiciona um dictionary de itens em outro dictionary

Arrays no Swift suportam o operador + = para adicionar o conteúdo de um Array a outro. Existe uma maneira fácil de fazer isso para um dictionary?

por exemplo:

var dict1 = ["a" : "foo"] var dict2 = ["b" : "bar"] var combinedDict = ... (some way of combining dict1 & dict2 without looping) 

Você pode definir o operador += para o Dictionary , por exemplo,

 func +=  (left: inout [K:V], right: [K:V]) { for (k, v) in right { left[k] = v } } 

E se

 dict2.forEach { (k,v) in dict1[k] = v } 

Isso adiciona todas as chaves e valores do dict2 ao dict1.

Atualmente, olhando para o Swift Standard Library Reference para Dictionary, não há como atualizar facilmente um dictionary com outro.

Você pode escrever uma extensão para fazer isso

 var dict1 = ["a" : "foo"] var dict2 = ["b" : "bar"] extension Dictionary { mutating func update(other:Dictionary) { for (key,value) in other { self.updateValue(value, forKey:key) } } } dict1.update(dict2) // dict1 is now ["a" : "foo", "b" : "bar] 

No Swift 4, deve-se usar a merging(_:uniquingKeysWith:) :

Exemplo:

 let dictA = ["x" : 1, "y": 2, "z": 3] let dictB = ["x" : 11, "y": 22, "w": 0] let resultA = dictA.merging(dictB, uniquingKeysWith: { (first, _) in first }) let resultB = dictA.merging(dictB, uniquingKeysWith: { (_, last) in last }) print(resultA) // ["x": 1, "y": 2, "z": 3, "w": 0] print(resultB) // ["x": 11, "y": 22, "z": 3, "w": 0] 

Não é construído na biblioteca do Swift, mas você pode adicionar o que quiser com a sobrecarga do operador, por exemplo:

 func + (left: Dictionary, right: Dictionary) -> Dictionary { var map = Dictionary() for (k, v) in left { map[k] = v } for (k, v) in right { map[k] = v } return map } 

Isso sobrecarrega o operador + para Dicionários que você pode usar agora para adicionar dictionarys com o operador + , por exemplo:

 var dict1 = ["a" : "foo"] var dict2 = ["b" : "bar"] var dict3 = dict1 + dict2 // ["a": "foo", "b": "bar"] 

Swift 3:

 extension Dictionary { mutating func merge(with dictionary: Dictionary) { dictionary.forEach { updateValue($1, forKey: $0) } } func merged(with dictionary: Dictionary) -> Dictionary { var dict = self dict.merge(with: dictionary) return dict } } let a = ["a":"b"] let b = ["1":"2"] let c = a.merged(with: b) print(c) //["a": "b", "1": "2"] 

Swift 2.0

 extension Dictionary { mutating func unionInPlace(dictionary: Dictionary) { dictionary.forEach { self.updateValue($1, forKey: $0) } } func union(var dictionary: Dictionary) -> Dictionary { dictionary.unionInPlace(self) return dictionary } } 

Imutável

Eu prefiro combinar / unir dictionarys imutáveis ​​com o operador + , então eu implementei como:

 // Swift 2 func +  (left: Dictionary, right: Dictionary?) -> Dictionary { guard let right = right else { return left } return left.reduce(right) { var new = $0 as [K:V] new.updateValue($1.1, forKey: $1.0) return new } } let moreAttributes: [String:AnyObject] = ["Function":"authenticate"] let attributes: [String:AnyObject] = ["File":"Auth.swift"] attributes + moreAttributes + nil //["Function": "authenticate", "File": "Auth.swift"] attributes + moreAttributes //["Function": "authenticate", "File": "Auth.swift"] attributes + nil //["File": "Auth.swift"] 

Mutável

 // Swift 2 func +=  (inout left: Dictionary, right: Dictionary?) { guard let right = right else { return } right.forEach { key, value in left.updateValue(value, forKey: key) } } let moreAttributes: [String:AnyObject] = ["Function":"authenticate"] var attributes: [String:AnyObject] = ["File":"Auth.swift"] attributes += nil //["File": "Auth.swift"] attributes += moreAttributes //["File": "Auth.swift", "Function": "authenticate"] 

O Swift 4 fornece merging(_:uniquingKeysWith:) , portanto, para o seu caso:

 let combinedDict = dict1.merging(dict2) { $1 } 

O fechamento abreviado retorna $1 , portanto, o valor de dict2 será usado quando houver um conflito com as chaves.

Uma variante mais legível usando uma extensão.

 extension Dictionary { func merge(dict: Dictionary) -> Dictionary { var mutableCopy = self for (key, value) in dict { // If both dictionaries have a value for same key, the value of the other dictionary is used. mutableCopy[key] = value } return mutableCopy } } 

Não há necessidade de ter extensões de dictionary agora. O dictionary Swift (Xcode 9.0+) tem uma funcionalidade para isso. Dê uma olhada aqui . Abaixo está um exemplo de como usá-lo

  var oldDictionary = ["a": 1, "b": 2] var newDictionary = ["a": 10000, "b": 10000, "c": 4] oldDictionary.merge(newDictionary) { (oldValue, newValue) -> Int in // This closure return what value to consider if repeated keys are found return newValue } print(oldDictionary) // Prints ["b": 10000, "a": 10000, "c": 4] 

Você pode tentar isso

  var dict1 = ["a" : "foo"] var dict2 = ["b" : "bar"] var temp = NSMutableDictionary(dictionary: dict1); temp .addEntriesFromDictionary(dict2) 

Você também pode usar reduzir para mesclá-los. Tente isso no playground

 let d1 = ["a":"foo","b":"bar"] let d2 = ["c":"car","d":"door"] let d3 = d1.reduce(d2) { (var d, p) in d[p.0] = p.1 return d } 

Eu recomendo a biblioteca SwifterSwift . No entanto, se você não quiser usar toda a biblioteca e todos os seus grandes acréscimos, você pode usar a extensão do Dicionário:

Swift 3+

 public extension Dictionary { public static func +=(lhs: inout [Key: Value], rhs: [Key: Value]) { rhs.forEach({ lhs[$0] = $1}) } } 

Você pode iterar sobre as combinações de valores-chave com o valor que deseja mesclar e adicioná-las por meio do método updateValue (forKey :):

 dictionaryTwo.forEach { dictionaryOne.updateValue($1, forKey: $0) } 

Agora todos os valores do dictionaryTwo foram adicionados ao dictionaryOne.

O mesmo que a resposta do @ farhadf, mas adotado para o Swift 3:

 let sourceDict1 = [1: "one", 2: "two"] let sourceDict2 = [3: "three", 4: "four"] let result = sourceDict1.reduce(sourceDict2) { (partialResult , pair) in var partialResult = partialResult //without this line we could not modify the dictionary partialResult[pair.0] = pair.1 return partialResult } 

A biblioteca ExSwift fornece mesclagem de dictionary (chamada Union e definida como o operador de pipe ‘|’), bem como várias outras funções de conveniência para os tipos básicos.

Você pode adicionar uma extensão do Dictionary como esta:

 extension Dictionary { func mergedWith(otherDictionary: [Key: Value]) -> [Key: Value] { var mergedDict: [Key: Value] = [:] [self, otherDictionary].forEach { dict in for (key, value) in dict { mergedDict[key] = value } } return mergedDict } } 

Então o uso é tão simples quanto o seguinte:

 var dict1 = ["a" : "foo"] var dict2 = ["b" : "bar"] var combinedDict = dict1.mergedWith(dict2) // => ["a": "foo", "b": "bar"] 

Se você preferir um framework que também inclua alguns resources mais úteis , faça o checkout do HandySwift . Basta importá-lo para o seu projeto e você pode usar o código acima sem adicionar extensões ao projeto.

Swift 3, extensão do dictionary:

 public extension Dictionary { public static func +=(lhs: inout Dictionary, rhs: Dictionary) { for (k, v) in rhs { lhs[k] = v } } } 

Você pode usar a function bridgeToObjectiveC () para tornar o dictionary um NSDictionary.

Será como o seguinte:

 var dict1 = ["a":"Foo"] var dict2 = ["b":"Boo"] var combinedDict = dict1.bridgeToObjectiveC() var mutiDict1 : NSMutableDictionary! = combinedDict.mutableCopy() as NSMutableDictionary var combineDict2 = dict2.bridgeToObjectiveC() var combine = mutiDict1.addEntriesFromDictionary(combineDict2) 

Então você pode converter o NSDictionary (combinar) de volta ou fazer o que quiser.

 import Foundation let x = ["a":1] let y = ["b":2] let out = NSMutableDictionary(dictionary: x) out.addEntriesFromDictionary(y) 

O resultado é um NSMutableDictionary não um dictionary typescript pelo Swift, mas a syntax para usá-lo é a mesma ( out["a"] == 1 neste caso), então você só teria um problema se estivesse usando terceiros código que espera um dictionary Swift, ou realmente precisa da verificação de tipo.

A resposta curta aqui é que você realmente tem que fazer um loop. Mesmo se você não estiver digitando isso explicitamente, é o que o método que você está chamando (addEntriesFromDictionary: here) serve. Eu sugiro que, se você não souber ao certo por que esse seria o caso, você deve considerar como mesclar os nós de folhas de duas trees B.

Se você realmente precisar de um tipo de dictionary nativo Swift em retorno, sugiro:

 let x = ["a":1] let y = ["b":2] var out = x for (k, v) in y { out[k] = v } 

A desvantagem dessa abordagem é que o índice do dictionary – no entanto, é feito – pode ser reconstruído várias vezes no loop, portanto, na prática, isso é cerca de 10 vezes mais lento do que a abordagem NSMutableDictionary.

Todas essas respostas são complicadas. Esta é a minha solução para o swift 2.2:

  //get first dictionnary let finalDictionnary : NSMutableDictionary = self.getBasicDict() //cast second dictionnary as [NSObject : AnyObject] let secondDictionnary : [NSObject : AnyObject] = self.getOtherDict() as [NSObject : AnyObject] //merge dictionnary into the first one finalDictionnary.addEntriesFromDictionary(secondDictionnary) 

Eu apenas usaria a biblioteca do dólar .

https://github.com/ankurp/Dollar/#merge—merge-1

Mescla todos os dictionarys juntos e o último dictionary substitui o valor em uma determinada chave

 let dict: Dictionary = ["Dog": 1, "Cat": 2] let dict2: Dictionary = ["Cow": 3] let dict3: Dictionary = ["Sheep": 4] $.merge(dict, dict2, dict3) => ["Dog": 1, "Cat": 2, "Cow": 3, "Sheep": 4] 

Minhas necessidades eram diferentes, eu precisava mesclar conjuntos de dados nesteds incompletos sem ter que ser derrotado.

 merging: ["b": [1, 2], "s": Set([5, 6]), "a": 1, "d": ["x": 2]] with ["b": [3, 4], "s": Set([6, 7]), "a": 2, "d": ["y": 4]] yields: ["b": [1, 2, 3, 4], "s": Set([5, 6, 7]), "a": 2, "d": ["y": 4, "x": 2]] 

Isso foi mais difícil do que eu queria que fosse. O desafio estava no mapeamento da digitação dinâmica para a tipagem estática e usei protocolos para resolver isso.

Também é digno de nota que, quando você usa a syntax literal do dictionary, você realmente obtém os tipos de base, que não selecionam as extensões de protocolo. Abortei meus esforços para apoiar aqueles, pois não consegui encontrar uma maneira fácil de validar a uniformidade dos elementos da coleção.

 import UIKit private protocol Mergable { func mergeWithSame(right: T) -> T? } public extension Dictionary { /** Merge Dictionaries - Parameter left: Dictionary to update - Parameter right: Source dictionary with values to be merged - Returns: Merged dictionay */ func merge(right:Dictionary) -> Dictionary { var merged = self for (k, rv) in right { // case of existing left value if let lv = self[k] { if let lv = lv as? Mergable where lv.dynamicType == rv.dynamicType { let m = lv.mergeWithSame(rv) merged[k] = m } else if lv is Mergable { assert(false, "Expected common type for matching keys!") } else if !(lv is Mergable), let _ = lv as? NSArray { assert(false, "Dictionary literals use incompatible Foundation Types") } else if !(lv is Mergable), let _ = lv as? NSDictionary { assert(false, "Dictionary literals use incompatible Foundation Types") } else { merged[k] = rv } } // case of no existing value else { merged[k] = rv } } return merged } } extension Array: Mergable { func mergeWithSame(right: T) -> T? { if let right = right as? Array { return (self + right) as? T } assert(false) return nil } } extension Dictionary: Mergable { func mergeWithSame(right: T) -> T? { if let right = right as? Dictionary { return self.merge(right) as? T } assert(false) return nil } } extension Set: Mergable { func mergeWithSame(right: T) -> T? { if let right = right as? Set { return self.union(right) as? T } assert(false) return nil } } var dsa12 = Dictionary() dsa12["a"] = 1 dsa12["b"] = [1, 2] dsa12["s"] = Set([5, 6]) dsa12["d"] = ["c":5, "x": 2] var dsa34 = Dictionary() dsa34["a"] = 2 dsa34["b"] = [3, 4] dsa34["s"] = Set([6, 7]) dsa34["d"] = ["c":-5, "y": 4] //let dsa2 = ["a": 1, "b":a34] let mdsa3 = dsa12.merge(dsa34) print("merging:\n\t\(dsa12)\nwith\n\t\(dsa34) \nyields: \n\t\(mdsa3)") 

Swift 2.2

 func + (left: [K : V], right: [K : V]) -> [K : V] { var result = [K:V]() for (key,value) in left { result[key] = value } for (key,value) in right { result[key] = value } return result }