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


81

如何使用将一个附加Dictionary到另一个?DictionarySwift

我正在使用AlamoFire图书馆将传送JSONREST server

字典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]'操作数




嘿@ the-nomad,您能否将接受的答案移至两次以上否决票-请:-)?
blackjacx

Answers:


61
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


我在哪里可以把extension有这个function在我的代码可在任何地方?对不起,我是菜鸟!
Nomad 2014年

1
把它放在项目中的任何文件

如果值也是字典怎么办,如何进行深度合并?
罗德里戈·鲁伊斯

@RodrigoRuiz我不认为这有什么用,只要您的原始字典也具有相同的体系结构,就不会有所不同(除非原始字典的类型[Key: Any]
Septronic,

1
由于Dictionary有了自己的合并功能,因此不再需要该扩展。请参阅stackoverflow.com/a/43615143/971329
blackjacx

153

我喜欢这种方法:

dicFrom.forEach { (key, value) in dicTo[key] = value }

斯威夫特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 返回新字典

16

对于Swift> = 2.2:
let parameters = dict1.reduce(dict2) { r, e in var r = r; r[e.0] = e.1; return r }

对于Swift <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 }

挖周围的标准库这是非常重要的:mapreducedropFirstforEach等都是简洁的代码的主食。功能位很有趣!


Swift 2.2编译器引发警告:“'var'参数已过时,将在Swift 3中删除”
Dheeraj Vepakomma

7

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

7
func +=<Key, Value> (lhs: inout [Key: Value], rhs: [Key: Value]) {
    rhs.forEach{ lhs[$0] = $1 }
}

var dic1 = ["test1": 1]

dic1 += ["test2": 2]

dic1  // ["test2": 2, "test1": 1]

4

我们可以使用merge关键字以更好的方式合并字典

var dictionary = ["a": 1, "b": 2]
/// Keeping existing value for key "a":
dictionary.merge(["a": 3, "c": 4]) { (current, _) in current }
 // ["b": 2, "a": 1, "c": 4]

3

我的需求有所不同,我想合并而不是笨手笨脚。

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

试试这个方法

    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

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

-1

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

将其更改为var关键字,它将为您工作。

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

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

dict1 += dict2
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.