如何在 Swift 中组合两个 Dictionary 实例?

问题描述 投票:0回答:12

如何使用 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]”操作数

ios json xcode dictionary swift
12个回答
277
投票

我喜欢这种方法:

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
    返回一个新字典

90
投票
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


19
投票

对于 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
等是简洁代码的主要内容。功能性的部分很有趣!


16
投票
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]

9
投票

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

5
投票

用于合并 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]

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

3
投票

您可以使用以下代码在 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
    }
}

2
投票

尝试这个方法

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

}

希望有帮助!!


1
投票

为什么不使用reduce:

let combined = dict1.reduce(into: dict2, { partialResult, dict1 in
    partialResult.updateValue(dict1.value, forKey: dict1.key)
})

复杂性
O(n),其中 n 是序列的长度。


0
投票

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

-1
投票

您正在使用 let 关键字来声明字典,因此您无法对字典进行更改,因为它用于声明常量。

将其更改为 var 关键字,这样它就适合你了。

var dict1: [String: AnyObject] = [
            kFacebook: [
                kToken: token
            ]
        ]

var dict2: [String: AnyObject] = [
        kRequest: [
            kTargetUserId: userId
        ]
    ]

dict1 += dict2
© www.soinside.com 2019 - 2024. All rights reserved.