How do you add a Dictionary of items into another Dictionary
DictionarySwiftDictionary Problem Overview
Arrays in Swift support the += operator to add the contents of one Array to another. Is there an easy way to do that for a dictionary?
eg:
var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]
var combinedDict = ... (some way of combining dict1 & dict2 without looping)
Dictionary Solutions
Solution 1 - Dictionary
You can define +=
operator for Dictionary
, e.g.,
func += <K, V> (left: inout [K:V], right: [K:V]) {
for (k, v) in right {
left[k] = v
}
}
Solution 2 - Dictionary
In Swift 4, one should use merging(_:uniquingKeysWith:)
:
Example:
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]
Solution 3 - Dictionary
How about
dict2.forEach { (k,v) in dict1[k] = v }
That adds all of dict2's keys and values into dict1.
Solution 4 - Dictionary
Swift 4 provides merging(_:uniquingKeysWith:)
, so for your case:
let combinedDict = dict1.merging(dict2) { $1 }
The shorthand closure returns $1
, therefore dict2's value will be used when there is a conflict with the keys.
Solution 5 - Dictionary
Currently, looking at the Swift Standard Library Reference for Dictionary, there is no way to easy update a dictionary with another one.
You can write an extension to do it
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]
Solution 6 - Dictionary
It's not built into the Swift library but you can add what you want with operator overloading, e.g:
func + <K,V>(left: Dictionary<K,V>, right: Dictionary<K,V>)
-> Dictionary<K,V>
{
var map = Dictionary<K,V>()
for (k, v) in left {
map[k] = v
}
for (k, v) in right {
map[k] = v
}
return map
}
This overloads the +
operator for Dictionaries which you can now use to add dictionaries with the +
operator, e.g:
var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]
var dict3 = dict1 + dict2 // ["a": "foo", "b": "bar"]
Solution 7 - Dictionary
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"]
Solution 8 - Dictionary
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
}
}
Solution 9 - Dictionary
No need to have any dictionary extensions now. Swift(Xcode 9.0+) dictionary has got a functionality for this. Have a look here. Below here is an example on how to use it
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]
Solution 10 - Dictionary
#Immutable
I prefer to combine/unite immutable dictionaries with +
operator so I implemented it like:
// Swift 2
func + <K,V> (left: Dictionary<K,V>, right: Dictionary<K,V>?) -> Dictionary<K,V> {
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"]
#Mutable
// Swift 2
func += <K,V> (inout left: Dictionary<K,V>, right: Dictionary<K,V>?) {
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"]
Solution 11 - Dictionary
You can try this
var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]
var temp = NSMutableDictionary(dictionary: dict1);
temp.addEntriesFromDictionary(dict2)
Solution 12 - Dictionary
A more readable variant using an extension.
extension Dictionary {
func merge(dict: Dictionary<Key,Value>) -> Dictionary<Key,Value> {
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
}
}
Solution 13 - Dictionary
You can also use reduce to merge them. Try this in the 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
}
Solution 14 - Dictionary
Some even more streamlined overloads for Swift 4:
extension Dictionary {
static func += (lhs: inout [Key:Value], rhs: [Key:Value]) {
lhs.merge(rhs){$1}
}
static func + (lhs: [Key:Value], rhs: [Key:Value]) -> [Key:Value] {
return lhs.merging(rhs){$1}
}
}
Solution 15 - Dictionary
I recommend the SwifterSwift Library. However, if you don't want to use the entire library and all its great additions you can just make use of their extension of Dictionary:
Swift 3+
public extension Dictionary {
public static func +=(lhs: inout [Key: Value], rhs: [Key: Value]) {
rhs.forEach({ lhs[$0] = $1})
}
}
Solution 16 - Dictionary
You can iterate over the Key Value combinations ob the value you want to merge and add them via the updateValue(forKey:) method:
dictionaryTwo.forEach {
dictionaryOne.updateValue($1, forKey: $0)
}
Now all values of dictionaryTwo got added to dictionaryOne.
Solution 17 - Dictionary
There is no need extension or any extra func anymore. You can write like that :
firstDictionary.merge(secondDictionary) { (value1, value2) -> AnyObject in
return object2 // what you want to return if keys same.
}
Solution 18 - Dictionary
The same as @farhadf's answer but adopted for 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
}
Solution 19 - Dictionary
Swift 3, dictionary extension:
public extension Dictionary {
public static func +=(lhs: inout Dictionary, rhs: Dictionary) {
for (k, v) in rhs {
lhs[k] = v
}
}
}
Solution 20 - Dictionary
You can use,
func addAll(from: [String: Any], into: [String: Any]){
from.forEach {into[$0] = $1}
}
Solution 21 - Dictionary
You can add a Dictionary
extension like this:
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
}
}
Then usage is as simple as the following:
var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]
var combinedDict = dict1.mergedWith(dict2)
// => ["a": "foo", "b": "bar"]
If you prefer a framework that also includes some more handy features then checkout HandySwift. Just import it to your project and you can use the above code without adding any extensions to the project yourself.
Solution 22 - Dictionary
You can use the bridgeToObjectiveC() function to make the dictionary a NSDictionary.
Will be like the following:
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)
Then you can convert the NSDictionary(combine) back or do whatever.
Solution 23 - Dictionary
All of these responses are complicated. This is my solution for 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)
Solution 24 - Dictionary
import Foundation
let x = ["a":1]
let y = ["b":2]
let out = NSMutableDictionary(dictionary: x)
out.addEntriesFromDictionary(y)
The result is an NSMutableDictionary not a Swift typed dictionary, but the syntax to use it is the same (out["a"] == 1
in this case) so you'd only have a problem if you're using third-party code which expects a Swift dictionary, or really need the type checking.
The short answer here is that you actually do have to loop. Even if you're not entering it explicitly, that's what the method you're calling (addEntriesFromDictionary: here) will do. I'd suggest if you're a bit unclear on why that would be the case you should consider how you would merge the leaf nodes of two B-trees.
If you really actually need a Swift native dictionary type in return, I'd suggest:
let x = ["a":1]
let y = ["b":2]
var out = x
for (k, v) in y {
out[k] = v
}
The downside of this approach is that the dictionary index - however it's done - may be rebuilt several times in the loop, so in practice this is about 10x slower than the NSMutableDictionary approach.
Solution 25 - Dictionary
My needs were different, I needed to merge incomplete nested data sets without clobbering.
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]]
This was harder than I wanted it to be. The challenge was in mapping from dynamic typing to static typing, and I used protocols to solve this.
Also worthy of note is that when you use the dictionary literal syntax, you actually get the foundation types, which do not pick up the protocol extensions. I aborted my efforts to support those as I couldn't find an easy to to validate the uniformity of the collection elements.
import UIKit
private protocol Mergable {
func mergeWithSame<T>(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<T>(right: T) -> T? {
if let right = right as? Array {
return (self + right) as? T
}
assert(false)
return nil
}
}
extension Dictionary: Mergable {
func mergeWithSame<T>(right: T) -> T? {
if let right = right as? Dictionary {
return self.merge(right) as? T
}
assert(false)
return nil
}
}
extension Set: Mergable {
func mergeWithSame<T>(right: T) -> T? {
if let right = right as? Set {
return self.union(right) as? T
}
assert(false)
return nil
}
}
var dsa12 = Dictionary<String, Any>()
dsa12["a"] = 1
dsa12["b"] = [1, 2]
dsa12["s"] = Set([5, 6])
dsa12["d"] = ["c":5, "x": 2]
var dsa34 = Dictionary<String, Any>()
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)")
Solution 26 - Dictionary
Swift 2.2
func + <K,V>(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
}
Solution 27 - Dictionary
I would just use the Dollar library.
https://github.com/ankurp/Dollar/#merge---merge-1
Merges all of the dictionaries together and the latter dictionary overrides the value at a given key
let dict: Dictionary<String, Int> = ["Dog": 1, "Cat": 2]
let dict2: Dictionary<String, Int> = ["Cow": 3]
let dict3: Dictionary<String, Int> = ["Sheep": 4]
$.merge(dict, dict2, dict3)
=> ["Dog": 1, "Cat": 2, "Cow": 3, "Sheep": 4]
Solution 28 - Dictionary
Here is a nice extension I wrote...
extension Dictionary where Value: Any {
public func mergeOnto(target: [Key: Value]?) -> [Key: Value] {
guard let target = target else { return self }
return self.merging(target) { current, _ in current }
}
}
to use:
var dict1 = ["cat": 5, "dog": 6]
var dict2 = ["dog": 9, "rodent": 10]
dict1 = dict1.mergeOnto(target: dict2)
Then, dict1 will be modified to
["cat": 5, "dog": 6, "rodent": 10]