如何使用 Swift 将一个
Dictionary
附加到另一个 Dictionary
?
我正在使用
AlamoFire
库将 JSON 内容发送到 REST 服务器。
词典1
var dict1: [String: AnyObject] = [
kFacebook: [
kToken: token
]
]
词典2
var dict2: [String: AnyObject] = [
kRequest: [
kTargetUserId: userId
]
]
如何组合两个词典来制作如下所示的新词典?
let parameters: [String: AnyObject] = [
kFacebook: [
kToken: token
],
kRequest: [
kTargetUserId: userId
]
]
我已经尝试过
dict1 += dict2
,但我遇到了编译错误:
二元运算符“+=”不能应用于两个“[String : AnyObject]”操作数
我喜欢这种方法:
dicFrom.forEach { (key, value) in dicTo[key] = value }
Swift 4 和 5
Apple 在 Swift 4 中引入了一种更好的方法来合并两个字典:
let dictionary = ["a": 1, "b": 2]
let newKeyValues = ["a": 3, "b": 4]
let keepingCurrent = dictionary.merging(newKeyValues) { (current, _) in current }
// ["b": 2, "a": 1]
let replacingCurrent = dictionary.merging(newKeyValues) { (_, new) in new }
// ["b": 4, "a": 3]
这里有 2 个选项(与在容器上运行的大多数功能一样):
merge
改变现有字典merging
返回一个新字典var d1 = ["a": "b"]
var d2 = ["c": "e"]
extension Dictionary {
mutating func merge(dict: [Key: Value]){
for (k, v) in dict {
updateValue(v, forKey: k)
}
}
}
d1.merge(d2)
参考很棒的 Dollar & Cent 项目 https://github.com/ankurp/Cent/blob/master/Sources/Dictionary.swift
对于 Swift >= 2.2:
let parameters = dict1.reduce(dict2) { r, e in var r = r; r[e.0] = e.1; return r }
对于斯威夫特 < 2.2:
let parameters = dict1.reduce(dict2) { (var r, e) in r[e.0] = e.1; return r }
Swift 4 有一个新功能:
let parameters = dict1.reduce(into: dict2) { (r, e) in r[e.0] = e.1 }
深入研究标准库非常重要:
map
、reduce
、dropFirst
、forEach
等是简洁代码的主要内容。功能性的部分很有趣!
extension Dictionary {
static func +=(lhs: inout Self, rhs: Self) {
lhs.merge(rhs) { _ , new in new }
}
static func +=<S: Sequence>(lhs: inout Self, rhs: S) where S.Element == (Key, Value) {
lhs.merge(rhs) { _ , new in new }
}
}
var dic = ["test1": 1]
dic += ["test2": 2]
dic // ["test1": 1, "test2": 2]
dic += [("test2", 3),("test3", 4)]
dic // ["test3": 4, "test1": 1, "test2": 3]
SequenceType.forEach
(由Dictionary
实现)提供了一个优雅的解决方案,将一个字典的元素添加到另一个字典中。
dic1.forEach { dic2[$0] = $1 }
例如
func testMergeDictionaries() {
let dic1 = [1:"foo"]
var dic2 = [2:"bar"]
dic1.forEach { dic2[$0] = $1 }
XCTAssertEqual(dic2[1], "foo")
}
用于合并 2 个字典的 Swift 4+ 解决方案:
let dict1 = ["a": 1, "b": 2]
let dict2 = ["a": 3, "c": 4]
//In case of duplicate keys, values of dict1 will replace dict2
let result1 = dict1.merging(dict2) { (current, _) in current } //["a": 1, "b": 2, "c": 4]
//In case of duplicate keys, values of dict2 will replace dict1
let result2 = dict1.merging(dict2) { (_, new) in new } //["a": 3, "b": 2, "c": 4]
我的需求不同,我想要合并而不是破坏。
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)")
您可以使用以下代码在 Swift 中组合两个字典实例:
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
}
}
尝试这个方法
let dict1: [String: AnyObject] = ["kFacebook": ["kToken": "token"]]
let dict2: [String: AnyObject] = ["kRequest": ["kTargetUserId": "userId"]]
var combinedAttributes : NSMutableDictionary!
combinedAttributes = NSMutableDictionary(dictionary: dict1)
combinedAttributes.addEntriesFromDictionary(dict2)
println(combinedAttributes)
它将打印以下内容:
{
kFacebook = {
kToken = token;
};
kRequest = {
kTargetUserId = userId;
};
}
希望有帮助!!
为什么不使用reduce:
let combined = dict1.reduce(into: dict2, { partialResult, dict1 in
partialResult.updateValue(dict1.value, forKey: dict1.key)
})
复杂性
O(n),其中 n 是序列的长度。
Swift 5+ 使用值条件合并两个字典
var dept1 : [String : String] = ["Production": "03/08/2024", "Quality":"02/14/2024"]
let dept2 : [String : String] = ["Development": "01/26/2024", "Production":"02/20/2024"]
dept1.merge(dept2){(firstValue, secondValue) in
return firstValue.dateValue > firstValue.dateValue ? firstValue : secondValue
}
extension String {
var dateValue: Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "mm/dd/YYYY"
return dateFormatter.date(from: self) ?? Date()
}
}
结果是部门1
["Quality": "02/14/2024", "Development": "01/26/2024", "Production": "03/08/2024"]
您正在使用 let 关键字来声明字典,因此您无法对字典进行更改,因为它用于声明常量。
将其更改为 var 关键字,这样它就适合你了。
var dict1: [String: AnyObject] = [
kFacebook: [
kToken: token
]
]
var dict2: [String: AnyObject] = [
kRequest: [
kTargetUserId: userId
]
]
dict1 += dict2