如何将条目字典添加到另一个字典中

Swift 中的数组支持 + = 运算符将一个数组的内容添加到另一个数组中。有什么简单的方法可以做到这一点吗?

例如:

var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]


var combinedDict = ... (some way of combining dict1 & dict2 without looping)
130654 次浏览

目前,看看 快速标准图书馆参考资料 for Dictionary,没有办法简单地用另一个字典来更新一个字典。

你可以写一个扩展来做这件事

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]

它不是内置在斯威夫特图书馆,但你可以添加你想要的运算符重载,例如:

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
}

这会重载 Dictionary 的 +操作符,您现在可以使用这个操作符通过 +操作符添加 Dictionary,例如:

var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]


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

您可以为 Dictionary定义 +=运算符,例如,

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

可以使用 bridgeToObjectiveC ()函数使字典成为 NSDictionary。

将会如下:

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)

然后您可以将 NSDictionary (组合)转换回来,或者执行任何操作。

你可以试试这个

var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]


var temp = NSMutableDictionary(dictionary: dict1);
temp.addEntriesFromDictionary(dict2)

您也可以使用 reduce 来合并它们

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
}

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
}
}

永恒不变

我更喜欢将不可变字典与 +操作符组合/联合起来,所以我的实现方式如下:

// 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"]

易变的

// 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"]

使用扩展名的更易读的变体。

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
}
}

我的需求是不同的,我需要合并不完整的嵌套数据集而不是重复。

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]]

这比我想象的要难。挑战在于从动态类型到静态类型的映射,我使用协议来解决这个问题。

同样值得注意的是,当您使用字典文字语法时,实际上得到的是基础类型,而不是协议扩展。我放弃了支持这些元素的努力,因为我找不到一个简单的方法来验证集合元素的一致性。

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)")

所有这些回答都很复杂,下面是我对快速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)
import Foundation


let x = ["a":1]
let y = ["b":2]


let out = NSMutableDictionary(dictionary: x)
out.addEntriesFromDictionary(y)

结果是一个 NSMutableDictionary 而不是 Swift 类型的字典,但是使用它的语法是相同的(在本例中是 out["a"] == 1) ,所以只有在使用第三方代码时才会出现问题,因为第三方代码需要 Swift 类型的字典,或者真的需要类型检查。

这里的简短答案是,您实际上必须循环。即使您没有显式地输入它,那也是您正在调用的方法(addEntriesFromDictionary: here)要做的。我建议,如果你还不清楚为什么会出现这种情况,你应该考虑如何合并两棵 B 树的叶节点。

如果您真的需要 Swift 本地字典类型作为回报,我建议:

let x = ["a":1]
let y = ["b":2]


var out = x
for (k, v) in y {
out[k] = v
}

这种方法的缺点是字典索引可能会在循环中重新构建好几次,所以实际上这比 NSMutableDictionary 方法慢10倍。

你可以像这样添加一个 Dictionary分机:

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
}
}

那么 用途就是如下的 很简单:

var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]


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

如果你喜欢一个框架,也包括一些 更方便的功能,然后签出 翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳。只需 将其导入到项目中和您可以使用上述代码 没有任何扩展的项目自己。

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
}

怎么样

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

它将所有 dict2的键和值添加到 dict1中。

斯威夫特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"]

与@farhadf 的回答相同,但是被 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
}

我会使用 一美元库。

Https://github.com/ankurp/dollar/#merge——-merge-1

将所有字典合并在一起,后一个字典覆盖给定键的值

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]

您可以遍历要合并的值的键值组合,然后通过 updateValue (forKey:)方法添加它们:

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

现在 DictionaryTwo 的所有值都被添加到 DictionaryOne 中。

我推荐 SwifterSwift 图书馆。然而,如果你不想使用整个库以及它所有的附加功能,你可以使用 Dictionary 的扩展:

Swift 3 +

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

Swift 3,字典扩展:

public extension Dictionary {


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


}

现在不需要任何字典扩展了。Swift (Xcode 9.0 +) dictionary 为此提供了一个功能。看看 给你。下面是一个如何使用它的例子

  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]

在 Swift 4中,应该使用 merging(_:uniquingKeysWith:):

例如:

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]

Swift 4 提供 merging(_:uniquingKeysWith:),因此对于您的情况:

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

速记闭包返回 $1,因此当与键发生冲突时将使用 dict2的值。

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}
}
}

这是我写的一个不错的扩展..。

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 }
}
}

使用方法:

var dict1 = ["cat": 5, "dog": 6]
var dict2 = ["dog": 9, "rodent": 10]


dict1 = dict1.mergeOnto(target: dict2)

然后,dict1将被修改为

["cat": 5, "dog": 6, "rodent": 10]


不再需要扩展或任何额外的功能了。 你可以这样写:

firstDictionary.merge(secondDictionary) { (value1, value2) -> AnyObject in
return object2 // what you want to return if keys same.
}

你可以用,

func addAll(from: [String: Any], into: [String: Any]){
from.forEach {into[$0] = $1}
}